Introduce X509_add_cert[s] simplifying various additions to cert lists
[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  * secret or pkey must be set. Attempts doing PBMAC in case 'secret' is set
30  * and else 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) {
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 (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->cert != NULL && ctx->pkey != NULL) {
149         /* make sure that our own cert is included in the first position */
150         if (!X509_add_cert(msg->extraCerts, ctx->cert,
151                            X509_ADD_FLAG_UP_REF | X509_ADD_FLAG_NO_DUP
152                            | X509_ADD_FLAG_PREPEND))
153             return 0;
154         /* if we have untrusted certs, try to add intermediate certs */
155         if (ctx->untrusted_certs != NULL) {
156             STACK_OF(X509) *chain =
157                 ossl_cmp_build_cert_chain(ctx->untrusted_certs, ctx->cert);
158             int res = X509_add_certs(msg->extraCerts, chain,
159                                      X509_ADD_FLAG_UP_REF | X509_ADD_FLAG_NO_DUP
160                                      | X509_ADD_FLAG_NO_SS);
161
162             sk_X509_pop_free(chain, X509_free);
163             if (res == 0)
164                 return 0;
165         }
166     }
167
168     /* add any additional certificates from ctx->extraCertsOut */
169     if (!X509_add_certs(msg->extraCerts, ctx->extraCertsOut,
170                         X509_ADD_FLAG_UP_REF | X509_ADD_FLAG_NO_DUP))
171         return 0;
172
173     /* if none was found avoid empty ASN.1 sequence */
174     if (sk_X509_num(msg->extraCerts) == 0) {
175         sk_X509_free(msg->extraCerts);
176         msg->extraCerts = NULL;
177     }
178     return 1;
179 }
180
181 /*
182  * Create an X509_ALGOR structure for PasswordBasedMAC protection based on
183  * the pbm settings in the context
184  * returns pointer to X509_ALGOR on success, NULL on error
185  */
186 static X509_ALGOR *create_pbmac_algor(OSSL_CMP_CTX *ctx)
187 {
188     X509_ALGOR *alg = NULL;
189     OSSL_CRMF_PBMPARAMETER *pbm = NULL;
190     unsigned char *pbm_der = NULL;
191     int pbm_der_len;
192     ASN1_STRING *pbm_str = NULL;
193
194     if (!ossl_assert(ctx != NULL))
195         return NULL;
196
197     alg = X509_ALGOR_new();
198     pbm = OSSL_CRMF_pbmp_new(ctx->pbm_slen, ctx->pbm_owf, ctx->pbm_itercnt,
199                              ctx->pbm_mac);
200     pbm_str = ASN1_STRING_new();
201     if (alg == NULL || pbm == NULL || pbm_str == NULL)
202         goto err;
203
204     if ((pbm_der_len = i2d_OSSL_CRMF_PBMPARAMETER(pbm, &pbm_der)) < 0)
205         goto err;
206
207     if (!ASN1_STRING_set(pbm_str, pbm_der, pbm_der_len))
208         goto err;
209     OPENSSL_free(pbm_der);
210
211     X509_ALGOR_set0(alg, OBJ_nid2obj(NID_id_PasswordBasedMAC),
212                     V_ASN1_SEQUENCE, pbm_str);
213     OSSL_CRMF_PBMPARAMETER_free(pbm);
214     return alg;
215
216  err:
217     ASN1_STRING_free(pbm_str);
218     X509_ALGOR_free(alg);
219     OPENSSL_free(pbm_der);
220     OSSL_CRMF_PBMPARAMETER_free(pbm);
221     return NULL;
222 }
223
224 int ossl_cmp_msg_protect(OSSL_CMP_CTX *ctx, OSSL_CMP_MSG *msg)
225 {
226     if (!ossl_assert(ctx != NULL && msg != NULL))
227         return 0;
228
229     /*
230      * For the case of re-protection remove pre-existing protection.
231      * TODO: Consider also removing any pre-existing extraCerts.
232      */
233     X509_ALGOR_free(msg->header->protectionAlg);
234     msg->header->protectionAlg = NULL;
235     ASN1_BIT_STRING_free(msg->protection);
236     msg->protection = NULL;
237
238     if (ctx->unprotectedSend)
239         return 1;
240
241     /* use PasswordBasedMac according to 5.1.3.1 if secretValue is given */
242     if (ctx->secretValue != NULL) {
243         if ((msg->header->protectionAlg = create_pbmac_algor(ctx)) == NULL)
244             goto err;
245         if (ctx->referenceValue != NULL
246                 && !ossl_cmp_hdr_set1_senderKID(msg->header,
247                                                 ctx->referenceValue))
248             goto err;
249     } else if (ctx->cert != NULL && ctx->pkey != NULL) {
250         /*
251          * use MSG_SIG_ALG according to 5.1.3.3 if client Certificate and
252          * private key is given
253          */
254         const ASN1_OCTET_STRING *subjKeyIDStr = NULL;
255         int algNID = 0;
256         ASN1_OBJECT *alg = NULL;
257
258         /* make sure that key and certificate match */
259         if (!X509_check_private_key(ctx->cert, ctx->pkey)) {
260             CMPerr(0, CMP_R_CERT_AND_KEY_DO_NOT_MATCH);
261             goto err;
262         }
263
264         if ((msg->header->protectionAlg = X509_ALGOR_new()) == NULL)
265             goto err;
266         if (!OBJ_find_sigid_by_algs(&algNID, ctx->digest,
267                                     EVP_PKEY_id(ctx->pkey))) {
268             CMPerr(0, CMP_R_UNSUPPORTED_KEY_TYPE);
269             goto err;
270         }
271         if ((alg = OBJ_nid2obj(algNID)) == NULL)
272             goto err;
273         if (!X509_ALGOR_set0(msg->header->protectionAlg, alg,
274                              V_ASN1_UNDEF, NULL)) {
275             ASN1_OBJECT_free(alg);
276             goto err;
277         }
278
279         /*
280          * set senderKID to keyIdentifier of the used certificate according
281          * to section 5.1.1
282          */
283         subjKeyIDStr = X509_get0_subject_key_id(ctx->cert);
284         if (subjKeyIDStr == NULL)
285             subjKeyIDStr = ctx->referenceValue; /* fallback */
286         if (subjKeyIDStr != NULL
287                 && !ossl_cmp_hdr_set1_senderKID(msg->header, subjKeyIDStr))
288             goto err;
289     } else {
290         CMPerr(0, CMP_R_MISSING_KEY_INPUT_FOR_CREATING_PROTECTION);
291         goto err;
292     }
293     if ((msg->protection =
294          ossl_cmp_calc_protection(msg, ctx->secretValue, ctx->pkey)) == NULL)
295         goto err;
296
297     /*
298      * If present, add ctx->cert followed by its chain as far as possible.
299      * Finally add any additional certificates from ctx->extraCertsOut;
300      * even if not needed to validate the protection
301      * the option to do this might be handy for certain use cases.
302      */
303     if (!ossl_cmp_msg_add_extraCerts(ctx, msg))
304         goto err;
305
306     /*
307      * As required by RFC 4210 section 5.1.1., if the sender name is not known
308      * to the client it set to NULL-DN. In this case for identification at least
309      * the senderKID must be set, where we took the referenceValue as fallback.
310      */
311     if (ossl_cmp_general_name_is_NULL_DN(msg->header->sender)
312             && msg->header->senderKID == NULL)
313         CMPerr(0, CMP_R_MISSING_SENDER_IDENTIFICATION);
314     else
315         return 1;
316
317  err:
318     CMPerr(0, CMP_R_ERROR_PROTECTING_MESSAGE);
319     return 0;
320 }