Commit 3ad344a5 authored by Dr. Stephen Henson's avatar Dr. Stephen Henson
Browse files

add suite B chain validation flags and associated verify errors

parent 6dbb6219
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -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
+6 −0
Original line number Diff line number Diff line
@@ -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;

+5 −0
Original line number Diff line number Diff line
@@ -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);
+124 −0
Original line number Diff line number Diff line
@@ -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);
	}
+12 −0
Original line number Diff line number Diff line
@@ -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);
Loading