Add -reqin_new_tid option to apps/cmp.c and OSSL_CMP_MSG_update_transactionID()
[openssl.git] / crypto / cmp / cmp_protect.c
index 7db3440f32bce3358f920458cf3801a51a9c24c4..0b87acd80449743621509976ee4e0b64ec795c5b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2007-2019 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2007-2020 The OpenSSL Project Authors. All Rights Reserved.
  * Copyright Nokia 2007-2019
  * Copyright Siemens AG 2015-2019
  *
@@ -18,6 +18,8 @@
 #include <openssl/err.h>
 #include <openssl/x509.h>
 
+DEFINE_STACK_OF(X509)
+
 /*
  * This function is also used for verification from cmp_vfy.
  *
@@ -35,7 +37,7 @@ ASN1_BIT_STRING *ossl_cmp_calc_protection(const OSSL_CMP_MSG *msg,
                                           EVP_PKEY *pkey)
 {
     ASN1_BIT_STRING *prot = NULL;
-    CMP_PROTECTEDPART prot_part;
+    OSSL_CMP_PROTECTEDPART prot_part;
     const ASN1_OBJECT *algorOID = NULL;
     int len;
     size_t prot_part_der_len;
@@ -58,7 +60,7 @@ ASN1_BIT_STRING *ossl_cmp_calc_protection(const OSSL_CMP_MSG *msg,
     prot_part.header = msg->header;
     prot_part.body = msg->body;
 
-    len = i2d_CMP_PROTECTEDPART(&prot_part, &prot_part_der);
+    len = i2d_OSSL_CMP_PROTECTEDPART(&prot_part, &prot_part_der);
     if (len < 0 || prot_part_der == NULL) {
         CMPerr(0, CMP_R_ERROR_CALCULATING_PROTECTION);
         goto end;
@@ -143,21 +145,18 @@ int ossl_cmp_msg_add_extraCerts(OSSL_CMP_CTX *ctx, OSSL_CMP_MSG *msg)
             && (msg->extraCerts = sk_X509_new_null()) == NULL)
         return 0;
 
-    if (ctx->clCert != NULL) {
-        /* Make sure that our own cert gets sent, in the first position */
-        if (!X509_up_ref(ctx->clCert))
-            return 0;
-        if (!sk_X509_push(msg->extraCerts, ctx->clCert)) {
-            X509_free(ctx->clCert);
+    if (ctx->clCert != NULL && ctx->pkey != NULL) {
+        /* make sure that our own cert is included in the first position */
+        if (!ossl_cmp_sk_X509_add1_cert(msg->extraCerts, ctx->clCert, 1, 1))
             return 0;
-        }
-        /* if we have untrusted store, try to add intermediate certs */
+        /* if we have untrusted certs, try to add intermediate certs */
         if (ctx->untrusted_certs != NULL) {
             STACK_OF(X509) *chain =
                 ossl_cmp_build_cert_chain(ctx->untrusted_certs, ctx->clCert);
             int res = ossl_cmp_sk_X509_add1_certs(msg->extraCerts, chain,
-                                                  1 /* no self-signed */,
+                                                  1 /* no self-issued */,
                                                   1 /* no duplicates */, 0);
+
             sk_X509_pop_free(chain, X509_free);
             if (res == 0)
                 return 0;
@@ -225,6 +224,15 @@ int ossl_cmp_msg_protect(OSSL_CMP_CTX *ctx, OSSL_CMP_MSG *msg)
     if (!ossl_assert(ctx != NULL && msg != NULL))
         return 0;
 
+    /*
+     * For the case of re-protection remove pre-existing protection.
+     * TODO: Consider also removing any pre-existing extraCerts.
+     */
+    X509_ALGOR_free(msg->header->protectionAlg);
+    msg->header->protectionAlg = NULL;
+    ASN1_BIT_STRING_free(msg->protection);
+    msg->protection = NULL;
+
     if (ctx->unprotectedSend)
         return 1;
 
@@ -236,77 +244,76 @@ int ossl_cmp_msg_protect(OSSL_CMP_CTX *ctx, OSSL_CMP_MSG *msg)
                 && !ossl_cmp_hdr_set1_senderKID(msg->header,
                                                 ctx->referenceValue))
             goto err;
-
-        /*
-         * add any additional certificates from ctx->extraCertsOut
-         * while not needed to validate the signing cert, the option to do
-         * this might be handy for certain use cases
-         */
-        if (!ossl_cmp_msg_add_extraCerts(ctx, msg))
-            goto err;
-
-        if ((msg->protection =
-             ossl_cmp_calc_protection(msg, ctx->secretValue, NULL)) == NULL)
-            goto err;
-    } else {
+    } else if (ctx->clCert != NULL && ctx->pkey != NULL) {
         /*
          * use MSG_SIG_ALG according to 5.1.3.3 if client Certificate and
          * private key is given
          */
-        if (ctx->clCert != NULL && ctx->pkey != NULL) {
-            const ASN1_OCTET_STRING *subjKeyIDStr = NULL;
-            int algNID = 0;
-            ASN1_OBJECT *alg = NULL;
-
-            /* make sure that key and certificate match */
-            if (!X509_check_private_key(ctx->clCert, ctx->pkey)) {
-                CMPerr(0, CMP_R_CERT_AND_KEY_DO_NOT_MATCH);
-                goto err;
-            }
-
-            if (msg->header->protectionAlg == NULL)
-                if ((msg->header->protectionAlg = X509_ALGOR_new()) == NULL)
-                    goto err;
+        const ASN1_OCTET_STRING *subjKeyIDStr = NULL;
+        int algNID = 0;
+        ASN1_OBJECT *alg = NULL;
 
-            if (!OBJ_find_sigid_by_algs(&algNID, ctx->digest,
-                                        EVP_PKEY_id(ctx->pkey))) {
-                CMPerr(0, CMP_R_UNSUPPORTED_KEY_TYPE);
-                goto err;
-            }
-            if ((alg = OBJ_nid2obj(algNID)) == NULL)
-                goto err;
-            if (!X509_ALGOR_set0(msg->header->protectionAlg,
-                                 alg, V_ASN1_UNDEF, NULL)) {
-                ASN1_OBJECT_free(alg);
-                goto err;
-            }
-
-            /*
-             * set senderKID to keyIdentifier of the used certificate according
-             * to section 5.1.1
-             */
-            subjKeyIDStr = X509_get0_subject_key_id(ctx->clCert);
-            if (subjKeyIDStr != NULL
-                    && !ossl_cmp_hdr_set1_senderKID(msg->header, subjKeyIDStr))
-                goto err;
+        /* make sure that key and certificate match */
+        if (!X509_check_private_key(ctx->clCert, ctx->pkey)) {
+            CMPerr(0, CMP_R_CERT_AND_KEY_DO_NOT_MATCH);
+            goto err;
+        }
 
-            /*
-             * Add ctx->clCert followed, if possible, by its chain built
-             * from ctx->untrusted_certs, and then ctx->extraCertsOut
-             */
-            if (!ossl_cmp_msg_add_extraCerts(ctx, msg))
+        if (msg->header->protectionAlg == NULL)
+            if ((msg->header->protectionAlg = X509_ALGOR_new()) == NULL)
                 goto err;
 
-            if ((msg->protection =
-                 ossl_cmp_calc_protection(msg, NULL, ctx->pkey)) == NULL)
-                goto err;
-        } else {
-            CMPerr(0, CMP_R_MISSING_KEY_INPUT_FOR_CREATING_PROTECTION);
+        if (!OBJ_find_sigid_by_algs(&algNID, ctx->digest,
+                                    EVP_PKEY_id(ctx->pkey))) {
+            CMPerr(0, CMP_R_UNSUPPORTED_KEY_TYPE);
             goto err;
         }
+        if ((alg = OBJ_nid2obj(algNID)) == NULL)
+            goto err;
+        if (!X509_ALGOR_set0(msg->header->protectionAlg, alg,
+                             V_ASN1_UNDEF, NULL)) {
+            ASN1_OBJECT_free(alg);
+            goto err;
+        }
+
+        /*
+         * set senderKID to keyIdentifier of the used certificate according
+         * to section 5.1.1
+         */
+        subjKeyIDStr = X509_get0_subject_key_id(ctx->clCert);
+        if (subjKeyIDStr == NULL)
+            subjKeyIDStr = ctx->referenceValue; /* fallback */
+        if (subjKeyIDStr != NULL
+                && !ossl_cmp_hdr_set1_senderKID(msg->header, subjKeyIDStr))
+            goto err;
+    } else {
+        CMPerr(0, CMP_R_MISSING_KEY_INPUT_FOR_CREATING_PROTECTION);
+        goto err;
     }
+    if ((msg->protection =
+         ossl_cmp_calc_protection(msg, ctx->secretValue, ctx->pkey)) == NULL)
+        goto err;
+
+    /*
+     * If present, add ctx->clCert followed by its chain as far as possible.
+     * Finally add any additional certificates from ctx->extraCertsOut;
+     * even if not needed to validate the protection
+     * the option to do this might be handy for certain use cases.
+     */
+    if (!ossl_cmp_msg_add_extraCerts(ctx, msg))
+        goto err;
+
+    /*
+     * As required by RFC 4210 section 5.1.1., if the sender name is not known
+     * to the client it set to NULL-DN. In this case for identification at least
+     * the senderKID must be set, where we took the referenceValue as fallback.
+     */
+    if (ossl_cmp_general_name_is_NULL_DN(msg->header->sender)
+            && msg->header->senderKID == NULL)
+        CMPerr(0, CMP_R_MISSING_SENDER_IDENTIFICATION);
+    else
+        return 1;
 
-    return 1;
  err:
     CMPerr(0, CMP_R_ERROR_PROTECTING_MESSAGE);
     return 0;