add suite B chain validation flags and associated verify errors

This commit is contained in:
Dr. Stephen Henson 2012-08-03 13:51:43 +00:00
parent 6dbb6219e7
commit 3ad344a517
7 changed files with 184 additions and 0 deletions

View file

@ -4,6 +4,10 @@
Changes between 1.0.1 and 1.1.0 [xx XXX xxxx]
*) New chain verification flags for Suite B levels of security. Check
algorithms are acceptable when flags are set in X509_verify_cert.
[Steve Henson]
*) Make tls1_check_chain return a set of flags indicating checks passed
by a certificate chain. Add additional tests to handle client
certificates: checks for matching certificate type and issuer name

View file

@ -2376,6 +2376,12 @@ int args_verify(char ***pargs, int *pargc,
flags |= X509_V_FLAG_CHECK_SS_SIGNATURE;
else if (!strcmp(arg, "-trusted_first"))
flags |= X509_V_FLAG_TRUSTED_FIRST;
else if (!strcmp(arg, "-suiteB_128_only"))
flags |= X509_V_FLAG_SUITEB_128_LOS_ONLY;
else if (!strcmp(arg, "-suiteB_128"))
flags |= X509_V_FLAG_SUITEB_128_LOS;
else if (!strcmp(arg, "-suiteB_192"))
flags |= X509_V_FLAG_SUITEB_192_LOS;
else
return 0;

View file

@ -966,6 +966,11 @@ int X509_REVOKED_set_revocationDate(X509_REVOKED *r, ASN1_TIME *tm);
int X509_REQ_check_private_key(X509_REQ *x509,EVP_PKEY *pkey);
int X509_check_private_key(X509 *x509,EVP_PKEY *pkey);
int X509_check_suiteb_chain(int *perror_depth,
X509 *x, STACK_OF(X509) *chain,
unsigned long flags);
int X509_check_suiteb_crl(X509_CRL *crl, EVP_PKEY *pk,
unsigned long flags);
int X509_issuer_and_serial_cmp(const X509 *a, const X509 *b);
unsigned long X509_issuer_and_serial_hash(X509 *a);

View file

@ -341,3 +341,127 @@ int X509_check_private_key(X509 *x, EVP_PKEY *k)
return 1;
return 0;
}
/* Check a suite B algorithm is permitted: pass in a public key and
* the NID of its signature (or 0 if no signature). The pflags is
* a pointer to a flags field which must contain the suite B verification
* flags.
*/
static int check_suite_b(EVP_PKEY *pkey, int sign_nid, unsigned long *pflags)
{
const EC_GROUP *grp = NULL;
int curve_nid;
if (pkey && pkey->type == EVP_PKEY_EC)
grp = EC_KEY_get0_group(pkey->pkey.ec);
if (!grp)
return X509_V_ERR_SUITE_B_INVALID_ALGORITHM;
curve_nid = EC_GROUP_get_curve_name(grp);
/* Check curve is consistent with LOS */
if (curve_nid == NID_secp384r1) /* P-384 */
{
/* Check signature algorithm is consistent with
* curve.
*/
if (sign_nid != -1 && sign_nid != NID_ecdsa_with_SHA384)
return X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM;
if (!(*pflags & X509_V_FLAG_SUITEB_192_LOS))
return X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED;
/* If we encounter P-384 we cannot use P-256 later */
*pflags &= ~X509_V_FLAG_SUITEB_128_LOS_ONLY;
}
else if (curve_nid == NID_X9_62_prime256v1) /* P-256 */
{
if (sign_nid != -1 && sign_nid != NID_ecdsa_with_SHA256)
return X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM;
if (!(*pflags & X509_V_FLAG_SUITEB_128_LOS_ONLY))
return X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED;
}
else
return X509_V_ERR_SUITE_B_INVALID_CURVE;
return X509_V_OK;
}
int X509_check_suiteb_chain(int *perror_depth, X509 *x, STACK_OF(X509) *chain,
unsigned long flags)
{
int rv, i, sign_nid;
EVP_PKEY *pk = NULL;
unsigned long tflags;
if (!(flags & X509_V_FLAG_SUITEB_128_LOS))
return X509_V_OK;
tflags = flags;
/* If no EE certificate passed in must be first in chain */
if (x == NULL)
{
x = sk_X509_value(chain, 0);
i = 1;
}
else
i = 0;
if (X509_get_version(x) != 2)
{
rv = X509_V_ERR_SUITE_B_INVALID_VERSION;
/* Correct error depth */
i = 0;
goto end;
}
pk = X509_get_pubkey(x);
/* Check EE key only */
rv = check_suite_b(pk, -1, &tflags);
if (rv != X509_V_OK)
{
/* Correct error depth */
i = 0;
goto end;
}
for(; i < sk_X509_num(chain); i++)
{
sign_nid = X509_get_signature_nid(x);
x = sk_X509_value(chain, i);
if (X509_get_version(x) != 2)
{
rv = X509_V_ERR_SUITE_B_INVALID_VERSION;
goto end;
}
EVP_PKEY_free(pk);
pk = X509_get_pubkey(x);
rv = check_suite_b(pk, sign_nid, &tflags);
if (rv != X509_V_OK)
goto end;
}
/* Final check: root CA signature */
rv = check_suite_b(pk, X509_get_signature_nid(x), &tflags);
end:
if (pk)
EVP_PKEY_free(pk);
if (rv != X509_V_OK)
{
/* Invalid signature or LOS errors are for previous cert */
if ((rv == X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM
|| rv == X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED) && i)
i--;
/* If we have LOS error and flags changed then we are signing
* P-384 with P-256. Use more meaninggul error.
*/
if (rv == X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED && flags != tflags)
rv = X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256;
if (perror_depth)
*perror_depth = i;
}
return rv;
}
int X509_check_suiteb_crl(X509_CRL *crl, EVP_PKEY *pk, unsigned long flags)
{
int sign_nid;
if (!(flags & X509_V_FLAG_SUITEB_128_LOS))
return X509_V_OK;
sign_nid = OBJ_obj2nid(crl->crl->sig_alg->algorithm);
return check_suite_b(pk, sign_nid, &flags);
}

View file

@ -185,6 +185,18 @@ const char *X509_verify_cert_error_string(long n)
return("CRL path validation error");
case X509_V_ERR_PATH_LOOP:
return("Path Loop");
case X509_V_ERR_SUITE_B_INVALID_VERSION:
return("Suite B: certificate version invalid");
case X509_V_ERR_SUITE_B_INVALID_ALGORITHM:
return("Suite B: invalid public key algorithm");
case X509_V_ERR_SUITE_B_INVALID_CURVE:
return("Suite B: invalid ECC curve");
case X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM:
return("Suite B: invalid signature algorithm");
case X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED:
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");
default:
BIO_snprintf(buf,sizeof buf,"error number %ld",n);

View file

@ -387,6 +387,17 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
ok = ctx->check_revocation(ctx);
if(!ok) goto end;
i = X509_check_suiteb_chain(&ctx->error_depth, NULL, ctx->chain,
ctx->param->flags);
if (i != X509_V_OK)
{
ctx->error = i;
ctx->current_cert = sk_X509_value(ctx->chain, ctx->error_depth);
ok = cb(0, ctx);
if (!ok)
goto end;
}
/* At this point, we have a chain and need to verify it */
if (ctx->verify != NULL)
ok=ctx->verify(ctx);
@ -1474,6 +1485,15 @@ static int check_crl(X509_STORE_CTX *ctx, X509_CRL *crl)
}
else
{
int rv;
rv = X509_check_suiteb_crl(crl, ikey, ctx->param->flags);
if (rv != X509_V_OK)
{
ctx->error=rv;
ok = ctx->verify_cb(0, ctx);
if (!ok)
goto err;
}
/* Verify CRL signature */
if(X509_CRL_verify(crl, ikey) <= 0)
{

View file

@ -355,6 +355,13 @@ void X509_STORE_CTX_set_depth(X509_STORE_CTX *ctx, int depth);
#define X509_V_ERR_CRL_PATH_VALIDATION_ERROR 54
/* Another issuer check debug option */
#define X509_V_ERR_PATH_LOOP 55
/* Suite B mode algorithm violation */
#define X509_V_ERR_SUITE_B_INVALID_VERSION 56
#define X509_V_ERR_SUITE_B_INVALID_ALGORITHM 57
#define X509_V_ERR_SUITE_B_INVALID_CURVE 58
#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
/* The application is not happy */
#define X509_V_ERR_APPLICATION_VERIFICATION 50
@ -393,6 +400,12 @@ void X509_STORE_CTX_set_depth(X509_STORE_CTX *ctx, int depth);
#define X509_V_FLAG_CHECK_SS_SIGNATURE 0x4000
/* Use trusted store first */
#define X509_V_FLAG_TRUSTED_FIRST 0x8000
/* Suite B 128 bit only mode: not normally used */
#define X509_V_FLAG_SUITEB_128_LOS_ONLY 0x10000
/* Suite B 192 bit only mode */
#define X509_V_FLAG_SUITEB_192_LOS 0x20000
/* Suite B 128 bit mode allowing 192 bit algorithms */
#define X509_V_FLAG_SUITEB_128_LOS 0x30000
#define X509_VP_FLAG_DEFAULT 0x1