Integrate host, email and IP address checks into X509_verify.

Add new verify options to set checks.

(backport from HEAD)
This commit is contained in:
Dr. Stephen Henson 2012-12-19 15:14:10 +00:00
parent db05bc512d
commit 70cd3c6b95
6 changed files with 195 additions and 0 deletions

View File

@ -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)]

View 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)++;

View 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);

View 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;

View 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);

View 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;