Integrate host, email and IP address checks into X509_verify.
authorDr. Stephen Henson <steve@openssl.org>
Wed, 5 Dec 2012 18:35:20 +0000 (18:35 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Wed, 5 Dec 2012 18:35:20 +0000 (18:35 +0000)
Add new verify options to set checks.

Remove previous -check* commands from s_client and s_server.

CHANGES
apps/apps.c
apps/s_client.c
apps/s_server.c
crypto/x509/x509_txt.c
crypto/x509/x509_vfy.c
crypto/x509/x509_vfy.h
crypto/x509/x509_vpm.c

diff --git a/CHANGES b/CHANGES
index 5f84cfd403c3d730f0ab578155020f3d995e013a..c4a7cb4fd14ff4f9a0116f4aaa443679640f8f7e 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -4,6 +4,10 @@
 
  Changes between 1.0.x and 1.1.0  [xx XXX xxxx]
 
+  *) Integrate hostname, email address and IP address checking with certificate
+     verification. New verify options supporting checking in opensl utility.
+     [Steve Henson]
+
   *) New function X509_CRL_diff to generate a delta CRL from the difference
      of two full CRLs. Add support to "crl" utility.
      [Steve Henson]
index 34dc70b35453a664e3a9913ee754501bef8dc928..adf78665b0d2a257da620e9bd04a9c7d4bc1e05d 100644 (file)
@@ -2382,6 +2382,8 @@ int args_verify(char ***pargs, int *pargc,
        char *arg = **pargs, *argn = (*pargs)[1];
        const X509_VERIFY_PARAM *vpm = NULL;
        time_t at_time = 0;
+       const unsigned char *hostname = NULL, *email = NULL;
+       char *ipasc = NULL;
        if (!strcmp(arg, "-policy"))
                {
                if (!argn)
@@ -2470,6 +2472,27 @@ int args_verify(char ***pargs, int *pargc,
                        }
                (*pargs)++;
                }
+       else if (strcmp(arg,"-verify_hostname") == 0)
+               {
+               if (!argn)
+                       *badarg = 1;
+               hostname = (unsigned char *)argn;
+               (*pargs)++;
+               }
+       else if (strcmp(arg,"-verify_email") == 0)
+               {
+               if (!argn)
+                       *badarg = 1;
+               email = (unsigned char *)argn;
+               (*pargs)++;
+               }
+       else if (strcmp(arg,"-verify_ip") == 0)
+               {
+               if (!argn)
+                       *badarg = 1;
+               ipasc = argn;
+               (*pargs)++;
+               }
        else if (!strcmp(arg, "-ignore_critical"))
                flags |= X509_V_FLAG_IGNORE_CRITICAL;
        else if (!strcmp(arg, "-issuer_checks"))
@@ -2538,6 +2561,15 @@ int args_verify(char ***pargs, int *pargc,
        if (at_time) 
                X509_VERIFY_PARAM_set_time(*pm, at_time);
 
+       if (hostname && !X509_VERIFY_PARAM_set1_host(*pm, hostname, 0))
+               *badarg = 1;
+
+       if (email && !X509_VERIFY_PARAM_set1_email(*pm, email, 0))
+               *badarg = 1;
+
+       if (ipasc && !X509_VERIFY_PARAM_set1_ip_asc(*pm, ipasc))
+               *badarg = 1;
+
        end:
 
        (*pargs)++;
index 7041fb49feab6870ebd93c52f74129b514d7e074..27c1696bf3cba5c26ca3d0e24e5c6c24d4627c33 100644 (file)
@@ -293,10 +293,6 @@ static void sc_usage(void)
        BIO_printf(bio_err," -host host     - use -connect instead\n");
        BIO_printf(bio_err," -port port     - use -connect instead\n");
        BIO_printf(bio_err," -connect host:port - who to connect to (default is %s:%s)\n",SSL_HOST_NAME,PORT_STR);
-       BIO_printf(bio_err," -checkhost host - check peer certificate matches \"host\"\n");
-       BIO_printf(bio_err," -checkemail email - check peer certificate matches \"email\"\n");
-       BIO_printf(bio_err," -checkip ipaddr - check peer certificate matches \"ipaddr\"\n");
-
        BIO_printf(bio_err," -verify arg   - turn on peer certificate verification\n");
        BIO_printf(bio_err," -cert arg     - certificate file to use, PEM format assumed\n");
        BIO_printf(bio_err," -certform arg - certificate format (PEM or DER) PEM default\n");
@@ -634,8 +630,6 @@ int MAIN(int argc, char **argv)
 #endif
        SSL_EXCERT *exc = NULL;
 
-       unsigned char *checkhost = NULL, *checkemail = NULL;
-       char *checkip = NULL;
        SSL_CONF_CTX *cctx = NULL;
        STACK_OF(OPENSSL_STRING) *ssl_args = NULL;
 
@@ -999,21 +993,6 @@ int MAIN(int argc, char **argv)
                        /* meth=TLSv1_client_method(); */
                        }
 #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)
                        {
@@ -1648,8 +1627,6 @@ SSL_set_tlsext_status_ids(con, ids);
                                                "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--;
 
index b9f6f30b0a7781d5a14aee37f89bc03d1bbb3d3e..2de85653677564bedb975d3ccf9015a0bba23b45 100644 (file)
@@ -473,9 +473,6 @@ static void sv_usage(void)
        BIO_printf(bio_err,"usage: s_server [args ...]\n");
        BIO_printf(bio_err,"\n");
        BIO_printf(bio_err," -accept arg   - port to accept on (default is %d)\n",PORT);
-       BIO_printf(bio_err," -checkhost host - check peer certificate matches \"host\"\n");
-       BIO_printf(bio_err," -checkemail email - check peer certificate matches \"email\"\n");
-       BIO_printf(bio_err," -checkip ipaddr - check peer certificate matches \"ipaddr\"\n");
        BIO_printf(bio_err," -context arg  - set session ID context\n");
        BIO_printf(bio_err," -verify arg   - turn on peer certificate verification\n");
        BIO_printf(bio_err," -Verify arg   - turn on peer certificate verification, must have a cert.\n");
@@ -946,9 +943,6 @@ static char *jpake_secret = NULL;
        static srpsrvparm srp_callback_parm;
 #endif
 static char *srtp_profiles = NULL;
-static unsigned char *checkhost = NULL, *checkemail = NULL;
-static char *checkip = NULL;
-
 
 int MAIN(int argc, char *argv[])
        {
@@ -1268,21 +1262,6 @@ int MAIN(int argc, char *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)
@@ -2578,8 +2557,6 @@ static int init_ssl_connection(SSL *con)
        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);
index 595efcead3707b98b8a347201fbecccfffb2e2c0..361cd21987d562ddd5b8e8f0f506ca541fdf9331 100644 (file)
@@ -197,6 +197,12 @@ const char *X509_verify_cert_error_string(long n)
                return("Suite B: curve not allowed for this LOS");
        case X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256:
                return("Suite B: cannot sign P-384 with P-256");
+       case X509_V_ERR_HOSTNAME_MISMATCH:
+               return("Hostname mismatch");
+       case X509_V_ERR_EMAIL_MISMATCH:
+               return("Email address mismatch");
+       case X509_V_ERR_IP_ADDRESS_MISMATCH:
+               return("IP address mismatch");
 
        default:
                BIO_snprintf(buf,sizeof buf,"error number %ld",n);
index a21fa39c327b59fa9f2941c20dfb64eb2da8d3ce..8ba03d5d43d41032e22ca083c72d18e2b691c4ab 100644 (file)
@@ -113,6 +113,7 @@ static int check_issued(X509_STORE_CTX *ctx, X509 *x, X509 *issuer);
 static X509 *find_issuer(X509_STORE_CTX *ctx, STACK_OF(X509) *sk, X509 *x);
 static int check_chain_extensions(X509_STORE_CTX *ctx);
 static int check_name_constraints(X509_STORE_CTX *ctx);
+static int check_id(X509_STORE_CTX *ctx);
 static int check_trust(X509_STORE_CTX *ctx);
 static int check_revocation(X509_STORE_CTX *ctx);
 static int check_cert(X509_STORE_CTX *ctx);
@@ -377,6 +378,10 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
        
        if (!ok) goto end;
 
+       ok = check_id(ctx);
+
+       if (!ok) goto end;
+
        /* We may as well copy down any DSA parameters that are required */
        X509_get_pubkey_parameters(NULL,ctx->chain);
 
@@ -694,6 +699,36 @@ static int check_name_constraints(X509_STORE_CTX *ctx)
        return 1;
        }
 
+static int check_id_error(X509_STORE_CTX *ctx, int errcode)
+       {
+       ctx->error = errcode;
+       ctx->current_cert = ctx->cert;
+       ctx->error_depth = 0;
+       return ctx->verify_cb(0, ctx);
+       }
+
+static int check_id(X509_STORE_CTX *ctx)
+       {
+       X509_VERIFY_PARAM *vpm = ctx->param;
+       X509 *x = ctx->cert;
+       if (vpm->host && !X509_check_host(x, vpm->host, vpm->hostlen, 0))
+               {
+               if (!check_id_error(ctx, X509_V_ERR_HOSTNAME_MISMATCH))
+                       return 0;
+               }
+       if (vpm->email && !X509_check_email(x, vpm->email, vpm->emaillen, 0))
+               {
+               if (!check_id_error(ctx, X509_V_ERR_EMAIL_MISMATCH))
+                       return 0;
+               }
+       if (vpm->ip && !X509_check_ip(x, vpm->ip, vpm->iplen, 0))
+               {
+               if (!check_id_error(ctx, X509_V_ERR_IP_ADDRESS_MISMATCH))
+                       return 0;
+               }
+       return 1;
+       }
+
 static int check_trust(X509_STORE_CTX *ctx)
 {
        int i, ok;
index a6f3943025e8527380279add28e40443d0998d07..58eff53f7211bd4c2dc2413b41de6d42b32adf1e 100644 (file)
@@ -173,6 +173,12 @@ typedef struct X509_VERIFY_PARAM_st
        int trust;              /* trust setting to check */
        int depth;              /* Verify depth */
        STACK_OF(ASN1_OBJECT) *policies;        /* Permissible policies */
+       unsigned char *host;    /* If not NULL hostname to match */
+       size_t hostlen;
+       unsigned char *email;   /* If not NULL email address to match */
+       size_t emaillen;
+       unsigned char *ip;      /* If not NULL IP address to match */
+       size_t iplen;           /* Length of IP address */
        } X509_VERIFY_PARAM;
 
 DECLARE_STACK_OF(X509_VERIFY_PARAM)
@@ -362,6 +368,10 @@ void X509_STORE_CTX_set_depth(X509_STORE_CTX *ctx, int depth);
 #define                X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM  59
 #define                X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED              60
 #define                X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256 61
+/* Host, email and IP check errors */
+#define                X509_V_ERR_HOSTNAME_MISMATCH                    62
+#define                X509_V_ERR_EMAIL_MISMATCH                       63
+#define                X509_V_ERR_IP_ADDRESS_MISMATCH                  64
 
 /* The application is not happy */
 #define                X509_V_ERR_APPLICATION_VERIFICATION             50
@@ -548,6 +558,15 @@ int X509_VERIFY_PARAM_add0_policy(X509_VERIFY_PARAM *param,
                                                ASN1_OBJECT *policy);
 int X509_VERIFY_PARAM_set1_policies(X509_VERIFY_PARAM *param, 
                                        STACK_OF(ASN1_OBJECT) *policies);
+
+int X509_VERIFY_PARAM_set1_host(X509_VERIFY_PARAM *param,
+                               const unsigned char *name, size_t namelen);
+int X509_VERIFY_PARAM_set1_email(X509_VERIFY_PARAM *param,
+                               const unsigned char *email, size_t emaillen);
+int X509_VERIFY_PARAM_set1_ip(X509_VERIFY_PARAM *param,
+                                       const unsigned char *ip, size_t iplen);
+int X509_VERIFY_PARAM_set1_ip_asc(X509_VERIFY_PARAM *param, const char *ipasc);
+
 int X509_VERIFY_PARAM_get_depth(const X509_VERIFY_PARAM *param);
 const char *X509_VERIFY_PARAM_get0_name(const X509_VERIFY_PARAM *param);
 
index 9e7d99666155df80cf5e1a6def27aeedfbc0d1a9..68f158435e0f8a9725b48aacc7cd4274a81a33b1 100644 (file)
@@ -83,6 +83,24 @@ static void x509_verify_param_zero(X509_VERIFY_PARAM *param)
                sk_ASN1_OBJECT_pop_free(param->policies, ASN1_OBJECT_free);
                param->policies = NULL;
                }
+       if (param->host)
+               {
+               OPENSSL_free(param->host);
+               param->host = NULL;
+               param->hostlen = 0;
+               }
+       if (param->email)
+               {
+               OPENSSL_free(param->email);
+               param->email = NULL;
+               param->emaillen = 0;
+               }
+       if (param->ip)
+               {
+               OPENSSL_free(param->ip);
+               param->ip = NULL;
+               param->iplen = 0;
+               }
        }
 
 X509_VERIFY_PARAM *X509_VERIFY_PARAM_new(void)
@@ -193,6 +211,24 @@ int X509_VERIFY_PARAM_inherit(X509_VERIFY_PARAM *dest,
                        return 0;
                }
 
+       if (test_x509_verify_param_copy(host, NULL))
+               {
+               if (!X509_VERIFY_PARAM_set1_host(dest, src->host, src->hostlen))
+                       return 0;
+               }
+
+       if (test_x509_verify_param_copy(email, NULL))
+               {
+               if (!X509_VERIFY_PARAM_set1_email(dest, src->email, src->emaillen))
+                       return 0;
+               }
+
+       if (test_x509_verify_param_copy(ip, NULL))
+               {
+               if (!X509_VERIFY_PARAM_set1_ip(dest, src->ip, src->iplen))
+                       return 0;
+               }
+
        return 1;
        }
 
@@ -207,6 +243,35 @@ int X509_VERIFY_PARAM_set1(X509_VERIFY_PARAM *to,
        return ret;
        }
 
+static int int_x509_param_set1(unsigned char **pdest, size_t *pdestlen,
+                               const unsigned char *src, size_t srclen)
+       {
+       void *tmp;
+       if (src)
+               {
+               if (srclen == 0)
+                       {
+                       tmp = BUF_strdup((char *)src);
+                       srclen = strlen((char *)src);
+                       }
+               else
+                       tmp = BUF_memdup(src, srclen);
+               if (!tmp)
+                       return 0;
+               }
+       else
+               {
+               tmp = NULL;
+               srclen = 0;
+               }
+       if (*pdest)
+               OPENSSL_free(*pdest);
+       *pdest = tmp;
+       if (pdestlen)
+               *pdestlen = srclen;
+       return 1;
+       }
+
 int X509_VERIFY_PARAM_set1_name(X509_VERIFY_PARAM *param, const char *name)
        {
        if (param->name)
@@ -306,6 +371,38 @@ int X509_VERIFY_PARAM_set1_policies(X509_VERIFY_PARAM *param,
        return 1;
        }
 
+int X509_VERIFY_PARAM_set1_host(X509_VERIFY_PARAM *param,
+                               const unsigned char *name, size_t namelen)
+       {
+       return int_x509_param_set1(&param->host, &param->hostlen,
+                                       name, namelen);
+       }
+
+int X509_VERIFY_PARAM_set1_email(X509_VERIFY_PARAM *param,
+                               const unsigned char *email, size_t emaillen)
+       {
+       return int_x509_param_set1(&param->email, &param->emaillen,
+                                       email, emaillen);
+       }
+
+int X509_VERIFY_PARAM_set1_ip(X509_VERIFY_PARAM *param,
+                                       const unsigned char *ip, size_t iplen)
+       {
+       if (iplen != 0 && iplen != 4 && iplen != 16)
+               return 0;
+       return int_x509_param_set1(&param->ip, &param->iplen, ip, iplen);
+       }
+
+int X509_VERIFY_PARAM_set1_ip_asc(X509_VERIFY_PARAM *param, const char *ipasc)
+       {
+       unsigned char ipout[16];
+       int iplen;
+       iplen = a2i_ipadd(ipout, ipasc);
+       if (iplen == 0)
+               return 0;
+       return X509_VERIFY_PARAM_set1_ip(param, ipout, (size_t)iplen);
+       }
+
 int X509_VERIFY_PARAM_get_depth(const X509_VERIFY_PARAM *param)
        {
        return param->depth;