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

(backport from HEAD)

CHANGES
apps/apps.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 1110d9e13a654a72798abc5fe38648a8322469b7..3097b95a00d7bb6f6c3fc919f9150166779cf570 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -4,6 +4,10 @@
 
  Changes between 1.0.1 and 1.0.2 [xx XXX xxxx]
 
+  *) Integrate hostname, email address and IP address checking with certificate
+     verification. New verify options supporting checking in opensl utility.
+     [Steve Henson]
+
   *) Fixes and wildcard matching support to hostname and email checking
      functions. Add manual page.
      [Florian Weimer (Red Hat Product Security Team)]
index fea5b25c1c732ad092d1afe32addd3a0a2d24422..24a493e0eb1bed7c41f5c799dfcf5dd5d31c4f01 100644 (file)
@@ -2262,6 +2262,8 @@ int args_verify(char ***pargs, int *pargc,
        char **oldargs = *pargs;
        char *arg = **pargs, *argn = (*pargs)[1];
        time_t at_time = 0;
+       const unsigned char *hostname = NULL, *email = NULL;
+       char *ipasc = NULL;
        if (!strcmp(arg, "-policy"))
                {
                if (!argn)
@@ -2335,6 +2337,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"))
@@ -2396,6 +2419,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 c44f753c462cb2be7d26e4b1c18eebd6f55a1c4c..e444176e90f0efe827828ea3237fa58bb613a78d 100644 (file)
@@ -184,6 +184,13 @@ const char *X509_verify_cert_error_string(long n)
        case X509_V_ERR_CRL_PATH_VALIDATION_ERROR:
                return("CRL path validation error");
 
+       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);
                return(buf);
index 49c8007967bd0f82e266d85cb7b6d4aad1941310..de075267bc57921993bceb93d261105d760b357d 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);
@@ -367,6 +368,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);
 
@@ -655,6 +660,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 ee40e7fe82583f93b39e3531f1a3c2360f138c83..40089cf50fcf91eecdf4957a56bf521bcfac7be7 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)
@@ -354,6 +360,11 @@ void X509_STORE_CTX_set_depth(X509_STORE_CTX *ctx, int depth);
 #define                X509_V_ERR_UNSUPPORTED_NAME_SYNTAX              53
 #define                X509_V_ERR_CRL_PATH_VALIDATION_ERROR            54
 
+/* 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
 
@@ -530,6 +541,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);
 
 int X509_VERIFY_PARAM_add0_table(X509_VERIFY_PARAM *param);
index dfd89d89faf0e885b2dca37ed1edcc11248c3aa0..7b3246f4775371c4d0e3a6a2c9cd1f588c1d8909 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;