aboutsummaryrefslogtreecommitdiffstats
path: root/crypto/x509
diff options
context:
space:
mode:
authorDr. Stephen Henson <steve@openssl.org>2012-08-03 13:51:43 +0000
committerDr. Stephen Henson <steve@openssl.org>2012-08-03 13:51:43 +0000
commit3ad344a5171c55511adddb96c805e037f2c061be (patch)
treeb5799e38c260f3f7851369a3d8666b953658c0c2 /crypto/x509
parent6dbb6219e7a6a5f94c9e7b0a25f0ce7c733f5060 (diff)
downloadopenssl-3ad344a5171c55511adddb96c805e037f2c061be.tar.gz
add suite B chain validation flags and associated verify errors
Diffstat (limited to 'crypto/x509')
-rw-r--r--crypto/x509/x509.h5
-rw-r--r--crypto/x509/x509_cmp.c124
-rw-r--r--crypto/x509/x509_txt.c12
-rw-r--r--crypto/x509/x509_vfy.c20
-rw-r--r--crypto/x509/x509_vfy.h13
5 files changed, 174 insertions, 0 deletions
diff --git a/crypto/x509/x509.h b/crypto/x509/x509.h
index 85f3c73a9f..88e5b4a475 100644
--- a/crypto/x509/x509.h
+++ b/crypto/x509/x509.h
@@ -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);
diff --git a/crypto/x509/x509_cmp.c b/crypto/x509/x509_cmp.c
index 352aa37434..74e076c7ba 100644
--- a/crypto/x509/x509_cmp.c
+++ b/crypto/x509/x509_cmp.c
@@ -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);
+ }
+
diff --git a/crypto/x509/x509_txt.c b/crypto/x509/x509_txt.c
index 9a0911a304..595efcead3 100644
--- a/crypto/x509/x509_txt.c
+++ b/crypto/x509/x509_txt.c
@@ -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);
diff --git a/crypto/x509/x509_vfy.c b/crypto/x509/x509_vfy.c
index 099881b7b3..508e4bd79e 100644
--- a/crypto/x509/x509_vfy.c
+++ b/crypto/x509/x509_vfy.c
@@ -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)
{
diff --git a/crypto/x509/x509_vfy.h b/crypto/x509/x509_vfy.h
index 34f2f113d5..2ac99c16a8 100644
--- a/crypto/x509/x509_vfy.h
+++ b/crypto/x509/x509_vfy.h
@@ -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