3e0c22bb80ac05855bcb3d147ea40adf48718711
[openssl.git] / crypto / cmp / cmp_protect.c
1 /*
2  * Copyright 2007-2020 The OpenSSL Project Authors. All Rights Reserved.
3  * Copyright Nokia 2007-2019
4  * Copyright Siemens AG 2015-2019
5  *
6  * Licensed under the Apache License 2.0 (the "License").  You may not use
7  * this file except in compliance with the License.  You can obtain a copy
8  * in the file LICENSE in the source distribution or at
9  * https://www.openssl.org/source/license.html
10  */
11
12 #include "cmp_local.h"
13
14 /* explicit #includes not strictly needed since implied by the above: */
15 #include <openssl/asn1t.h>
16 #include <openssl/cmp.h>
17 #include <openssl/crmf.h>
18 #include <openssl/err.h>
19 #include <openssl/x509.h>
20
21 DEFINE_STACK_OF(X509)
22
23 /*
24  * This function is also used for verification from cmp_vfy.
25  *
26  * Calculate protection for given PKImessage utilizing the given credentials
27  * and the algorithm parameters set inside the message header's protectionAlg.
28  *
29  * Either secret or pkey must be set, the other must be NULL. Attempts doing
30  * PBMAC in case 'secret' is set and signature if 'pkey' is set - but will only
31  * do the protection already marked in msg->header->protectionAlg.
32  *
33  * returns ptr to ASN1_BIT_STRING containing protection on success, else NULL
34  */
35 ASN1_BIT_STRING *ossl_cmp_calc_protection(const OSSL_CMP_MSG *msg,
36                                           const ASN1_OCTET_STRING *secret,
37                                           EVP_PKEY *pkey)
38 {
39     ASN1_BIT_STRING *prot = NULL;
40     OSSL_CMP_PROTECTEDPART prot_part;
41     const ASN1_OBJECT *algorOID = NULL;
42     int len;
43     size_t prot_part_der_len;
44     unsigned char *prot_part_der = NULL;
45     size_t sig_len;
46     unsigned char *protection = NULL;
47     const void *ppval = NULL;
48     int pptype = 0;
49     OSSL_CRMF_PBMPARAMETER *pbm = NULL;
50     ASN1_STRING *pbm_str = NULL;
51     const unsigned char *pbm_str_uc = NULL;
52     EVP_MD_CTX *evp_ctx = NULL;
53     int md_NID;
54     const EVP_MD *md = NULL;
55
56     if (!ossl_assert(msg != NULL))
57         return NULL;
58
59     /* construct data to be signed */
60     prot_part.header = msg->header;
61     prot_part.body = msg->body;
62
63     len = i2d_OSSL_CMP_PROTECTEDPART(&prot_part, &prot_part_der);
64     if (len < 0 || prot_part_der == NULL) {
65         CMPerr(0, CMP_R_ERROR_CALCULATING_PROTECTION);
66         goto end;
67     }
68     prot_part_der_len = (size_t) len;
69
70     if (msg->header->protectionAlg == NULL) {
71         CMPerr(0, CMP_R_UNKNOWN_ALGORITHM_ID);
72         goto end;
73     }
74     X509_ALGOR_get0(&algorOID, &pptype, &ppval, msg->header->protectionAlg);
75
76     if (secret != NULL && pkey == NULL) {
77         if (ppval == NULL) {
78             CMPerr(0, CMP_R_ERROR_CALCULATING_PROTECTION);
79             goto end;
80         }
81         if (NID_id_PasswordBasedMAC != OBJ_obj2nid(algorOID)) {
82             CMPerr(0, CMP_R_WRONG_ALGORITHM_OID);
83             goto end;
84         }
85         pbm_str = (ASN1_STRING *)ppval;
86         pbm_str_uc = pbm_str->data;
87         pbm = d2i_OSSL_CRMF_PBMPARAMETER(NULL, &pbm_str_uc, pbm_str->length);
88         if (pbm == NULL) {
89             CMPerr(0, CMP_R_WRONG_ALGORITHM_OID);
90             goto end;
91         }
92
93         if (!OSSL_CRMF_pbm_new(pbm, prot_part_der, prot_part_der_len,
94                                secret->data, secret->length,
95                                &protection, &sig_len))
96             goto end;
97     } else if (secret == NULL && pkey != NULL) {
98         /* TODO combine this with large parts of CRMF_poposigningkey_init() */
99         /* EVP_DigestSignInit() checks that pkey type is correct for the alg */
100
101         if (!OBJ_find_sigid_algs(OBJ_obj2nid(algorOID), &md_NID, NULL)
102                 || (md = EVP_get_digestbynid(md_NID)) == NULL
103                 || (evp_ctx = EVP_MD_CTX_new()) == NULL) {
104             CMPerr(0, CMP_R_UNKNOWN_ALGORITHM_ID);
105             goto end;
106         }
107         if (EVP_DigestSignInit(evp_ctx, NULL, md, NULL, pkey) <= 0
108                 || EVP_DigestSignUpdate(evp_ctx, prot_part_der,
109                                         prot_part_der_len) <= 0
110                 || EVP_DigestSignFinal(evp_ctx, NULL, &sig_len) <= 0
111                 || (protection = OPENSSL_malloc(sig_len)) == NULL
112                 || EVP_DigestSignFinal(evp_ctx, protection, &sig_len) <= 0) {
113             CMPerr(0, CMP_R_ERROR_CALCULATING_PROTECTION);
114             goto end;
115         }
116     } else {
117         CMPerr(0, CMP_R_INVALID_ARGS);
118         goto end;
119     }
120
121     if ((prot = ASN1_BIT_STRING_new()) == NULL)
122         goto end;
123     /* OpenSSL defaults all bit strings to be encoded as ASN.1 NamedBitList */
124     prot->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07);
125     prot->flags |= ASN1_STRING_FLAG_BITS_LEFT;
126     if (!ASN1_BIT_STRING_set(prot, protection, sig_len)) {
127         ASN1_BIT_STRING_free(prot);
128         prot = NULL;
129     }
130
131  end:
132     OSSL_CRMF_PBMPARAMETER_free(pbm);
133     EVP_MD_CTX_free(evp_ctx);
134     OPENSSL_free(protection);
135     OPENSSL_free(prot_part_der);
136     return prot;
137 }
138
139 int ossl_cmp_msg_add_extraCerts(OSSL_CMP_CTX *ctx, OSSL_CMP_MSG *msg)
140 {
141     if (!ossl_assert(ctx != NULL && msg != NULL))
142         return 0;
143
144     if (msg->extraCerts == NULL
145             && (msg->extraCerts = sk_X509_new_null()) == NULL)
146         return 0;
147
148     if (ctx->clCert != NULL) {
149         /* Make sure that our own cert gets sent, in the first position */
150         if (!X509_up_ref(ctx->clCert))
151             return 0;
152         if (!sk_X509_push(msg->extraCerts, ctx->clCert)) {
153             X509_free(ctx->clCert);
154             return 0;
155         }
156         /* if we have untrusted store, try to add intermediate certs */
157         if (ctx->untrusted_certs != NULL) {
158             STACK_OF(X509) *chain =
159                 ossl_cmp_build_cert_chain(ctx->untrusted_certs, ctx->clCert);
160             int res = ossl_cmp_sk_X509_add1_certs(msg->extraCerts, chain,
161                                                   1 /* no self-issued */,
162                                                   1 /* no duplicates */, 0);
163             sk_X509_pop_free(chain, X509_free);
164             if (res == 0)
165                 return 0;
166         }
167     }
168
169     /* add any additional certificates from ctx->extraCertsOut */
170     if (!ossl_cmp_sk_X509_add1_certs(msg->extraCerts, ctx->extraCertsOut, 0,
171                                      1 /* no duplicates */, 0))
172         return 0;
173
174     /* if none was found avoid empty ASN.1 sequence */
175     if (sk_X509_num(msg->extraCerts) == 0) {
176         sk_X509_free(msg->extraCerts);
177         msg->extraCerts = NULL;
178     }
179     return 1;
180 }
181
182 /*
183  * Create an X509_ALGOR structure for PasswordBasedMAC protection based on
184  * the pbm settings in the context
185  * returns pointer to X509_ALGOR on success, NULL on error
186  */
187 static X509_ALGOR *create_pbmac_algor(OSSL_CMP_CTX *ctx)
188 {
189     X509_ALGOR *alg = NULL;
190     OSSL_CRMF_PBMPARAMETER *pbm = NULL;
191     unsigned char *pbm_der = NULL;
192     int pbm_der_len;
193     ASN1_STRING *pbm_str = NULL;
194
195     if (!ossl_assert(ctx != NULL))
196         return NULL;
197
198     alg = X509_ALGOR_new();
199     pbm = OSSL_CRMF_pbmp_new(ctx->pbm_slen, ctx->pbm_owf, ctx->pbm_itercnt,
200                              ctx->pbm_mac);
201     pbm_str = ASN1_STRING_new();
202     if (alg == NULL || pbm == NULL || pbm_str == NULL)
203         goto err;
204
205     if ((pbm_der_len = i2d_OSSL_CRMF_PBMPARAMETER(pbm, &pbm_der)) < 0)
206         goto err;
207
208     if (!ASN1_STRING_set(pbm_str, pbm_der, pbm_der_len))
209         goto err;
210     OPENSSL_free(pbm_der);
211
212     X509_ALGOR_set0(alg, OBJ_nid2obj(NID_id_PasswordBasedMAC),
213                     V_ASN1_SEQUENCE, pbm_str);
214     OSSL_CRMF_PBMPARAMETER_free(pbm);
215     return alg;
216
217  err:
218     ASN1_STRING_free(pbm_str);
219     X509_ALGOR_free(alg);
220     OPENSSL_free(pbm_der);
221     OSSL_CRMF_PBMPARAMETER_free(pbm);
222     return NULL;
223 }
224
225 int ossl_cmp_msg_protect(OSSL_CMP_CTX *ctx, OSSL_CMP_MSG *msg)
226 {
227     if (!ossl_assert(ctx != NULL && msg != NULL))
228         return 0;
229
230     if (ctx->unprotectedSend)
231         return 1;
232
233     /* use PasswordBasedMac according to 5.1.3.1 if secretValue is given */
234     if (ctx->secretValue != NULL) {
235         if ((msg->header->protectionAlg = create_pbmac_algor(ctx)) == NULL)
236             goto err;
237         if (ctx->referenceValue != NULL
238                 && !ossl_cmp_hdr_set1_senderKID(msg->header,
239                                                 ctx->referenceValue))
240             goto err;
241
242         /*
243          * add any additional certificates from ctx->extraCertsOut
244          * while not needed to validate the signing cert, the option to do
245          * this might be handy for certain use cases
246          */
247         if (!ossl_cmp_msg_add_extraCerts(ctx, msg))
248             goto err;
249
250         if ((msg->protection =
251              ossl_cmp_calc_protection(msg, ctx->secretValue, NULL)) == NULL)
252             goto err;
253     } else {
254         /*
255          * use MSG_SIG_ALG according to 5.1.3.3 if client Certificate and
256          * private key is given
257          */
258         if (ctx->clCert != NULL && ctx->pkey != NULL) {
259             const ASN1_OCTET_STRING *subjKeyIDStr = NULL;
260             int algNID = 0;
261             ASN1_OBJECT *alg = NULL;
262
263             /* make sure that key and certificate match */
264             if (!X509_check_private_key(ctx->clCert, ctx->pkey)) {
265                 CMPerr(0, CMP_R_CERT_AND_KEY_DO_NOT_MATCH);
266                 goto err;
267             }
268
269             if (msg->header->protectionAlg == NULL)
270                 if ((msg->header->protectionAlg = X509_ALGOR_new()) == NULL)
271                     goto err;
272
273             if (!OBJ_find_sigid_by_algs(&algNID, ctx->digest,
274                                         EVP_PKEY_id(ctx->pkey))) {
275                 CMPerr(0, CMP_R_UNSUPPORTED_KEY_TYPE);
276                 goto err;
277             }
278             if ((alg = OBJ_nid2obj(algNID)) == NULL)
279                 goto err;
280             if (!X509_ALGOR_set0(msg->header->protectionAlg,
281                                  alg, V_ASN1_UNDEF, NULL)) {
282                 ASN1_OBJECT_free(alg);
283                 goto err;
284             }
285
286             /*
287              * set senderKID to keyIdentifier of the used certificate according
288              * to section 5.1.1
289              */
290             subjKeyIDStr = X509_get0_subject_key_id(ctx->clCert);
291             if (subjKeyIDStr == NULL)
292                 subjKeyIDStr = ctx->referenceValue; /* fallback */
293             if (subjKeyIDStr != NULL
294                     && !ossl_cmp_hdr_set1_senderKID(msg->header, subjKeyIDStr))
295                 goto err;
296
297             /*
298              * Add ctx->clCert followed, if possible, by its chain built
299              * from ctx->untrusted_certs, and then ctx->extraCertsOut
300              */
301             if (!ossl_cmp_msg_add_extraCerts(ctx, msg))
302                 goto err;
303
304             if ((msg->protection =
305                  ossl_cmp_calc_protection(msg, NULL, ctx->pkey)) == NULL)
306                 goto err;
307         } else {
308             CMPerr(0, CMP_R_MISSING_KEY_INPUT_FOR_CREATING_PROTECTION);
309             goto err;
310         }
311     }
312
313     /*
314      * As required by RFC 4210 section 5.1.1., if the sender name is not known
315      * to the client it set to NULL-DN. In this case for identification at least
316      * the senderKID must be set, where we took the referenceValue as fallback.
317      */
318
319     if (ossl_cmp_general_name_is_NULL_DN(msg->header->sender)
320             && msg->header->senderKID == NULL)
321         CMPerr(0, CMP_R_MISSING_SENDER_IDENTIFICATION);
322     else
323         return 1;
324
325  err:
326     CMPerr(0, CMP_R_ERROR_PROTECTING_MESSAGE);
327     return 0;
328 }