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.
This commit is contained in:
parent
c5f6da54fc
commit
a70da5b3ec
5
CHANGES
5
CHANGES
@ -4,6 +4,11 @@
|
|||||||
|
|
||||||
Changes between 1.0.x and 1.1.0 [xx XXX xxxx]
|
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
|
*) 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
|
received by client and send back to server. Also prints an abbreviated
|
||||||
summary of the connection parameters.
|
summary of the connection parameters.
|
||||||
|
29
apps/apps.c
29
apps/apps.c
@ -2791,6 +2791,35 @@ unsigned char *next_protos_parse(unsigned short *outlen, const char *in)
|
|||||||
}
|
}
|
||||||
#endif /* !OPENSSL_NO_TLSEXT && !OPENSSL_NO_NEXTPROTONEG */
|
#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
|
* Platform-specific sections
|
||||||
*/
|
*/
|
||||||
|
@ -335,6 +335,11 @@ void jpake_server_auth(BIO *out, BIO *conn, const char *secret);
|
|||||||
unsigned char *next_protos_parse(unsigned short *outlen, const char *in);
|
unsigned char *next_protos_parse(unsigned short *outlen, const char *in);
|
||||||
#endif /* !OPENSSL_NO_TLSEXT && !OPENSSL_NO_NEXTPROTONEG */
|
#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_UNDEF 0
|
||||||
#define FORMAT_ASN1 1
|
#define FORMAT_ASN1 1
|
||||||
#define FORMAT_TEXT 2
|
#define FORMAT_TEXT 2
|
||||||
|
@ -191,3 +191,7 @@ int args_excert(char ***pargs, int *pargc,
|
|||||||
int *badarg, BIO *err, SSL_EXCERT **pexc);
|
int *badarg, BIO *err, SSL_EXCERT **pexc);
|
||||||
int load_excert(SSL_EXCERT **pexc, BIO *err);
|
int load_excert(SSL_EXCERT **pexc, BIO *err);
|
||||||
void print_ssl_summary(BIO *bio, SSL *s);
|
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);
|
||||||
|
13
apps/s_cb.c
13
apps/s_cb.c
@ -1533,3 +1533,16 @@ void print_ssl_summary(BIO *bio, SSL *s)
|
|||||||
ssl_print_tmp_key(bio, s);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -634,6 +634,9 @@ int MAIN(int argc, char **argv)
|
|||||||
#endif
|
#endif
|
||||||
SSL_EXCERT *exc = NULL;
|
SSL_EXCERT *exc = NULL;
|
||||||
|
|
||||||
|
unsigned char *checkhost = NULL, *checkemail = NULL;
|
||||||
|
char *checkip = NULL;
|
||||||
|
|
||||||
meth=SSLv23_client_method();
|
meth=SSLv23_client_method();
|
||||||
|
|
||||||
apps_startup();
|
apps_startup();
|
||||||
@ -993,6 +996,21 @@ int MAIN(int argc, char **argv)
|
|||||||
client_sigalgs= *(++argv);
|
client_sigalgs= *(++argv);
|
||||||
}
|
}
|
||||||
#endif
|
#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
|
#ifndef OPENSSL_NO_JPAKE
|
||||||
else if (strcmp(*argv,"-jpake") == 0)
|
else if (strcmp(*argv,"-jpake") == 0)
|
||||||
{
|
{
|
||||||
@ -1628,6 +1646,8 @@ SSL_set_tlsext_status_ids(con, ids);
|
|||||||
"CONNECTION ESTABLISHED\n");
|
"CONNECTION ESTABLISHED\n");
|
||||||
print_ssl_summary(bio_err, con);
|
print_ssl_summary(bio_err, con);
|
||||||
}
|
}
|
||||||
|
print_ssl_cert_checks(bio_err, con, checkhost,
|
||||||
|
checkemail, checkip);
|
||||||
print_stuff(bio_c_out,con,full_log);
|
print_stuff(bio_c_out,con,full_log);
|
||||||
if (full_log > 0) full_log--;
|
if (full_log > 0) full_log--;
|
||||||
|
|
||||||
|
@ -1003,6 +1003,10 @@ int MAIN(int argc, char *argv[])
|
|||||||
char *srp_verifier_file = NULL;
|
char *srp_verifier_file = NULL;
|
||||||
#endif
|
#endif
|
||||||
SSL_EXCERT *exc = NULL;
|
SSL_EXCERT *exc = NULL;
|
||||||
|
|
||||||
|
unsigned char *checkhost = NULL, *checkemail = NULL;
|
||||||
|
char *checkip = NULL;
|
||||||
|
|
||||||
meth=SSLv23_server_method();
|
meth=SSLv23_server_method();
|
||||||
|
|
||||||
local_argc=argc;
|
local_argc=argc;
|
||||||
@ -1260,6 +1264,21 @@ int MAIN(int argc, char *argv[])
|
|||||||
client_sigalgs= *(++argv);
|
client_sigalgs= *(++argv);
|
||||||
}
|
}
|
||||||
#endif
|
#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)
|
else if (strcmp(*argv,"-msg") == 0)
|
||||||
{ s_msg=1; }
|
{ s_msg=1; }
|
||||||
else if (strcmp(*argv,"-msgfile") == 0)
|
else if (strcmp(*argv,"-msgfile") == 0)
|
||||||
@ -2661,6 +2680,8 @@ static int init_ssl_connection(SSL *con)
|
|||||||
if (s_brief)
|
if (s_brief)
|
||||||
print_ssl_summary(bio_err, con);
|
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));
|
PEM_write_bio_SSL_SESSION(bio_s_out,SSL_get_session(con));
|
||||||
|
|
||||||
peer=SSL_get_peer_certificate(con);
|
peer=SSL_get_peer_certificate(con);
|
||||||
|
19
apps/x509.c
19
apps/x509.c
@ -208,6 +208,8 @@ int MAIN(int argc, char **argv)
|
|||||||
int need_rand = 0;
|
int need_rand = 0;
|
||||||
int checkend=0,checkoffset=0;
|
int checkend=0,checkoffset=0;
|
||||||
unsigned long nmflag = 0, certflag = 0;
|
unsigned long nmflag = 0, certflag = 0;
|
||||||
|
unsigned char *checkhost = NULL, *checkemail = NULL;
|
||||||
|
char *checkip = NULL;
|
||||||
#ifndef OPENSSL_NO_ENGINE
|
#ifndef OPENSSL_NO_ENGINE
|
||||||
char *engine=NULL;
|
char *engine=NULL;
|
||||||
#endif
|
#endif
|
||||||
@ -456,6 +458,21 @@ int MAIN(int argc, char **argv)
|
|||||||
checkoffset=atoi(*(++argv));
|
checkoffset=atoi(*(++argv));
|
||||||
checkend=1;
|
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)
|
else if (strcmp(*argv,"-noout") == 0)
|
||||||
noout= ++num;
|
noout= ++num;
|
||||||
else if (strcmp(*argv,"-trustout") == 0)
|
else if (strcmp(*argv,"-trustout") == 0)
|
||||||
@ -1061,6 +1078,8 @@ bad:
|
|||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
print_cert_checks(STDout, x, checkhost, checkemail, checkip);
|
||||||
|
|
||||||
if (noout)
|
if (noout)
|
||||||
{
|
{
|
||||||
ret=0;
|
ret=0;
|
||||||
|
@ -568,6 +568,134 @@ void X509_email_free(STACK_OF(OPENSSL_STRING) *sk)
|
|||||||
sk_OPENSSL_STRING_pop_free(sk, str_free);
|
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
|
/* Convert IP addresses both IPv4 and IPv6 into an
|
||||||
* OCTET STRING compatible with RFC3280.
|
* OCTET STRING compatible with RFC3280.
|
||||||
*/
|
*/
|
||||||
|
@ -700,6 +700,18 @@ STACK_OF(OPENSSL_STRING) *X509_get1_email(X509 *x);
|
|||||||
STACK_OF(OPENSSL_STRING) *X509_REQ_get1_email(X509_REQ *x);
|
STACK_OF(OPENSSL_STRING) *X509_REQ_get1_email(X509_REQ *x);
|
||||||
void X509_email_free(STACK_OF(OPENSSL_STRING) *sk);
|
void X509_email_free(STACK_OF(OPENSSL_STRING) *sk);
|
||||||
STACK_OF(OPENSSL_STRING) *X509_get1_ocsp(X509 *x);
|
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(const char *ipasc);
|
||||||
ASN1_OCTET_STRING *a2i_IPADDRESS_NC(const char *ipasc);
|
ASN1_OCTET_STRING *a2i_IPADDRESS_NC(const char *ipasc);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user