Changes between 1.0.x and 1.1.0 [xx XXX xxxx]
+ *) New functions to check a hostname email or IP address against a
+ certificate. Add options to s_client, s_server and x509 utilities
+ to print results of checks against a certificate.
+ [Steve Henson]
+
*) Add -rev test option to s_server to just reverse order of characters
received by client and send back to server. Also prints an abbreviated
summary of the connection parameters.
}
#endif /* !OPENSSL_NO_TLSEXT && !OPENSSL_NO_NEXTPROTONEG */
+void print_cert_checks(BIO *bio, X509 *x,
+ const unsigned char *checkhost,
+ const unsigned char *checkemail,
+ const char *checkip)
+ {
+ if (x == NULL)
+ return;
+ if (checkhost)
+ {
+ BIO_printf(bio, "Hostname %s does%s match certificate\n",
+ checkhost, X509_check_host(x, checkhost, 0, 0)
+ ? "" : " NOT");
+ }
+
+ if (checkemail)
+ {
+ BIO_printf(bio, "Email %s does%s match certificate\n",
+ checkemail, X509_check_email(x, checkemail, 0,
+ 0) ? "" : " NOT");
+ }
+
+ if (checkip)
+ {
+ BIO_printf(bio, "IP %s does%s match certificate\n",
+ checkip, X509_check_ip_asc(x, checkip,
+ 0) ? "" : " NOT");
+ }
+ }
+
/*
* Platform-specific sections
*/
unsigned char *next_protos_parse(unsigned short *outlen, const char *in);
#endif /* !OPENSSL_NO_TLSEXT && !OPENSSL_NO_NEXTPROTONEG */
+void print_cert_checks(BIO *bio, X509 *x,
+ const unsigned char *checkhost,
+ const unsigned char *checkemail,
+ const char *checkip);
+
#define FORMAT_UNDEF 0
#define FORMAT_ASN1 1
#define FORMAT_TEXT 2
int *badarg, BIO *err, SSL_EXCERT **pexc);
int load_excert(SSL_EXCERT **pexc, BIO *err);
void print_ssl_summary(BIO *bio, SSL *s);
+void print_ssl_cert_checks(BIO *bio, SSL *s,
+ const unsigned char *checkhost,
+ const unsigned char *checkemail,
+ const char *checkip);
ssl_print_tmp_key(bio, s);
}
+void print_ssl_cert_checks(BIO *bio, SSL *s,
+ const unsigned char *checkhost,
+ const unsigned char *checkemail,
+ const char *checkip)
+ {
+ X509 *peer;
+ peer = SSL_get_peer_certificate(s);
+ if (peer)
+ {
+ print_cert_checks(bio, peer, checkhost, checkemail, checkip);
+ X509_free(peer);
+ }
+ }
#endif
SSL_EXCERT *exc = NULL;
+ unsigned char *checkhost = NULL, *checkemail = NULL;
+ char *checkip = NULL;
+
meth=SSLv23_client_method();
apps_startup();
client_sigalgs= *(++argv);
}
#endif
+ else if (strcmp(*argv,"-checkhost") == 0)
+ {
+ if (--argc < 1) goto bad;
+ checkhost=(unsigned char *)*(++argv);
+ }
+ else if (strcmp(*argv,"-checkemail") == 0)
+ {
+ if (--argc < 1) goto bad;
+ checkemail=(unsigned char *)*(++argv);
+ }
+ else if (strcmp(*argv,"-checkip") == 0)
+ {
+ if (--argc < 1) goto bad;
+ checkip=*(++argv);
+ }
#ifndef OPENSSL_NO_JPAKE
else if (strcmp(*argv,"-jpake") == 0)
{
"CONNECTION ESTABLISHED\n");
print_ssl_summary(bio_err, con);
}
+ print_ssl_cert_checks(bio_err, con, checkhost,
+ checkemail, checkip);
print_stuff(bio_c_out,con,full_log);
if (full_log > 0) full_log--;
char *srp_verifier_file = NULL;
#endif
SSL_EXCERT *exc = NULL;
+
+ unsigned char *checkhost = NULL, *checkemail = NULL;
+ char *checkip = NULL;
+
meth=SSLv23_server_method();
local_argc=argc;
client_sigalgs= *(++argv);
}
#endif
+ else if (strcmp(*argv,"-checkhost") == 0)
+ {
+ if (--argc < 1) goto bad;
+ checkhost=(unsigned char *)*(++argv);
+ }
+ else if (strcmp(*argv,"-checkemail") == 0)
+ {
+ if (--argc < 1) goto bad;
+ checkemail=(unsigned char *)*(++argv);
+ }
+ else if (strcmp(*argv,"-checkip") == 0)
+ {
+ if (--argc < 1) goto bad;
+ checkip=*(++argv);
+ }
else if (strcmp(*argv,"-msg") == 0)
{ s_msg=1; }
else if (strcmp(*argv,"-msgfile") == 0)
if (s_brief)
print_ssl_summary(bio_err, con);
+ print_ssl_cert_checks(bio_err, con, checkhost, checkemail, checkip);
+
PEM_write_bio_SSL_SESSION(bio_s_out,SSL_get_session(con));
peer=SSL_get_peer_certificate(con);
int need_rand = 0;
int checkend=0,checkoffset=0;
unsigned long nmflag = 0, certflag = 0;
+ unsigned char *checkhost = NULL, *checkemail = NULL;
+ char *checkip = NULL;
#ifndef OPENSSL_NO_ENGINE
char *engine=NULL;
#endif
checkoffset=atoi(*(++argv));
checkend=1;
}
+ else if (strcmp(*argv,"-checkhost") == 0)
+ {
+ if (--argc < 1) goto bad;
+ checkhost=(unsigned char *)*(++argv);
+ }
+ else if (strcmp(*argv,"-checkemail") == 0)
+ {
+ if (--argc < 1) goto bad;
+ checkemail=(unsigned char *)*(++argv);
+ }
+ else if (strcmp(*argv,"-checkip") == 0)
+ {
+ if (--argc < 1) goto bad;
+ checkip=*(++argv);
+ }
else if (strcmp(*argv,"-noout") == 0)
noout= ++num;
else if (strcmp(*argv,"-trustout") == 0)
goto end;
}
+ print_cert_checks(STDout, x, checkhost, checkemail, checkip);
+
if (noout)
{
ret=0;
sk_OPENSSL_STRING_pop_free(sk, str_free);
}
+/* Compare an ASN1_STRING to a supplied string. If they match
+ * return 1. If cmp_type > 0 only compare if string matches the
+ * type, otherwise convert it to UTF8.
+ */
+
+static int do_check_string(ASN1_STRING *a, int cmp_type,
+ const unsigned char *b, size_t blen)
+ {
+ if (!a->data || !a->length)
+ return 0;
+ if (cmp_type > 0)
+ {
+ if (cmp_type != a->type)
+ return 0;
+ if (a->length == (int)blen && !memcmp(a->data, b, blen))
+ return 1;
+ else
+ return 0;
+ }
+ else
+ {
+ int astrlen, rv;
+ unsigned char *astr;
+ astrlen = ASN1_STRING_to_UTF8(&astr, a);
+ if (astrlen < 0)
+ return 0;
+ if (astrlen == (int)blen && !memcmp(astr, b, blen))
+ rv = 1;
+ else
+ rv = 0;
+ OPENSSL_free(astr);
+ return rv;
+ }
+ }
+
+static int do_x509_check(X509 *x, const unsigned char *chk, size_t chklen,
+ unsigned int flags, int check_type)
+ {
+ GENERAL_NAMES *gens = NULL;
+ X509_NAME *name = NULL;
+ int i;
+ int cnid;
+ if (check_type == GEN_EMAIL)
+ cnid = NID_pkcs9_emailAddress;
+ else if (check_type == GEN_DNS)
+ cnid = NID_commonName;
+ else
+ cnid = 0;
+
+ if (chklen == 0)
+ chklen = strlen((const char *)chk);
+
+ gens = X509_get_ext_d2i(x, NID_subject_alt_name, NULL, NULL);
+ if (gens)
+ {
+ int rv = 0;
+ int alt_type;
+ if (cnid)
+ alt_type = V_ASN1_IA5STRING;
+ else
+ alt_type = V_ASN1_OCTET_STRING;
+ for (i = 0; i < sk_GENERAL_NAME_num(gens); i++)
+ {
+ GENERAL_NAME *gen;
+ ASN1_STRING *cstr;
+ gen = sk_GENERAL_NAME_value(gens, i);
+ if(gen->type != check_type)
+ continue;
+ if (check_type == GEN_EMAIL)
+ cstr = gen->d.rfc822Name;
+ else if (check_type == GEN_DNS)
+ cstr = gen->d.dNSName;
+ else
+ cstr = gen->d.iPAddress;
+ if (do_check_string(cstr, alt_type, chk, chklen))
+ {
+ rv = 1;
+ break;
+ }
+ }
+ GENERAL_NAMES_free(gens);
+ if (rv)
+ return 1;
+ if (!(flags & X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT) || !cnid)
+ return 0;
+ }
+ i = -1;
+ name = X509_get_subject_name(x);
+ while((i = X509_NAME_get_index_by_NID(name, cnid, i)) >= 0)
+ {
+ X509_NAME_ENTRY *ne;
+ ASN1_STRING *str;
+ ne = X509_NAME_get_entry(name, i);
+ str = X509_NAME_ENTRY_get_data(ne);
+ if (do_check_string(str, -1, chk, chklen))
+ return 1;
+ }
+ return 0;
+ }
+
+int X509_check_host(X509 *x, const unsigned char *chk, size_t chklen,
+ unsigned int flags)
+ {
+ return do_x509_check(x, chk, chklen, flags, GEN_DNS);
+ }
+
+int X509_check_email(X509 *x, const unsigned char *chk, size_t chklen,
+ unsigned int flags)
+ {
+ return do_x509_check(x, chk, chklen, flags, GEN_EMAIL);
+ }
+
+int X509_check_ip(X509 *x, const unsigned char *chk, size_t chklen,
+ unsigned int flags)
+ {
+ return do_x509_check(x, chk, chklen, flags, GEN_IPADD);
+ }
+
+int X509_check_ip_asc(X509 *x, const char *ipasc, unsigned int flags)
+ {
+ unsigned char ipout[16];
+ int iplen;
+ iplen = a2i_ipadd(ipout, ipasc);
+ if (iplen == 0)
+ return 0;
+ return do_x509_check(x, ipout, (size_t)iplen, flags, GEN_IPADD);
+ }
+
/* Convert IP addresses both IPv4 and IPv6 into an
* OCTET STRING compatible with RFC3280.
*/
STACK_OF(OPENSSL_STRING) *X509_REQ_get1_email(X509_REQ *x);
void X509_email_free(STACK_OF(OPENSSL_STRING) *sk);
STACK_OF(OPENSSL_STRING) *X509_get1_ocsp(X509 *x);
+/* Flags for X509_check_* functions */
+
+/* Always check subject name for host match even if subject alt names present */
+#define X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT 0x1
+
+int X509_check_host(X509 *x, const unsigned char *chk, size_t chklen,
+ unsigned int flags);
+int X509_check_email(X509 *x, const unsigned char *chk, size_t chklen,
+ unsigned int flags);
+int X509_check_ip(X509 *x, const unsigned char *chk, size_t chklen,
+ unsigned int flags);
+int X509_check_ip_asc(X509 *x, const char *ipasc, unsigned int flags);
ASN1_OCTET_STRING *a2i_IPADDRESS(const char *ipasc);
ASN1_OCTET_STRING *a2i_IPADDRESS_NC(const char *ipasc);