1 | /* |
2 | * Copyright 2007-2019 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 | /* CMP functions for PKIHeader handling */ |
13 | |
14 | #include "cmp_local.h" |
15 | |
16 | #include <openssl/rand.h> |
17 | |
18 | /* explicit #includes not strictly needed since implied by the above: */ |
19 | #include <openssl/asn1t.h> |
20 | #include <openssl/cmp.h> |
21 | #include <openssl/err.h> |
22 | |
23 | int ossl_cmp_hdr_set_pvno(OSSL_CMP_PKIHEADER *hdr, int pvno) |
24 | { |
25 | if (!ossl_assert(hdr != NULL)) |
26 | return 0; |
27 | return ASN1_INTEGER_set(hdr->pvno, pvno); |
28 | } |
29 | |
30 | int ossl_cmp_hdr_get_pvno(const OSSL_CMP_PKIHEADER *hdr) |
31 | { |
32 | int64_t pvno; |
33 | |
34 | if (!ossl_assert(hdr != NULL)) |
35 | return -1; |
36 | if (!ASN1_INTEGER_get_int64(&pvno, hdr->pvno) || pvno < 0 || pvno > INT_MAX) |
37 | return -1; |
38 | return (int)pvno; |
39 | } |
40 | |
41 | ASN1_OCTET_STRING *OSSL_CMP_HDR_get0_transactionID(const OSSL_CMP_PKIHEADER *hdr) |
42 | { |
43 | if (hdr == NULL) { |
44 | CMPerr(0, CMP_R_NULL_ARGUMENT); |
45 | return NULL; |
46 | } |
47 | return hdr->transactionID; |
48 | } |
49 | |
50 | ASN1_OCTET_STRING *ossl_cmp_hdr_get0_senderNonce(const OSSL_CMP_PKIHEADER *hdr) |
51 | { |
52 | if (!ossl_assert(hdr != NULL)) |
53 | return NULL; |
54 | return hdr->senderNonce; |
55 | } |
56 | |
57 | ASN1_OCTET_STRING *OSSL_CMP_HDR_get0_recipNonce(const OSSL_CMP_PKIHEADER *hdr) |
58 | { |
59 | if (hdr == NULL) { |
60 | CMPerr(0, CMP_R_NULL_ARGUMENT); |
61 | return NULL; |
62 | } |
63 | return hdr->recipNonce; |
64 | } |
65 | |
66 | /* assign to *tgt a copy of src (which may be NULL to indicate an empty DN) */ |
67 | static int set1_general_name(GENERAL_NAME **tgt, const X509_NAME *src) |
68 | { |
69 | GENERAL_NAME *gen; |
70 | |
71 | if (!ossl_assert(tgt != NULL)) |
72 | return 0; |
73 | if ((gen = GENERAL_NAME_new()) == NULL) |
74 | goto err; |
75 | gen->type = GEN_DIRNAME; |
76 | |
77 | if (src == NULL) { /* NULL-DN */ |
78 | if ((gen->d.directoryName = X509_NAME_new()) == NULL) |
79 | goto err; |
80 | } else if (!X509_NAME_set(&gen->d.directoryName, src)) { |
81 | goto err; |
82 | } |
83 | |
84 | GENERAL_NAME_free(*tgt); |
85 | *tgt = gen; |
86 | |
87 | return 1; |
88 | |
89 | err: |
90 | GENERAL_NAME_free(gen); |
91 | return 0; |
92 | } |
93 | |
94 | /* |
95 | * Set the sender name in PKIHeader. |
96 | * when nm is NULL, sender is set to an empty string |
97 | * returns 1 on success, 0 on error |
98 | */ |
99 | int ossl_cmp_hdr_set1_sender(OSSL_CMP_PKIHEADER *hdr, const X509_NAME *nm) |
100 | { |
101 | if (!ossl_assert(hdr != NULL)) |
102 | return 0; |
103 | return set1_general_name(&hdr->sender, nm); |
104 | } |
105 | |
106 | int ossl_cmp_hdr_set1_recipient(OSSL_CMP_PKIHEADER *hdr, const X509_NAME *nm) |
107 | { |
108 | if (!ossl_assert(hdr != NULL)) |
109 | return 0; |
110 | return set1_general_name(&hdr->recipient, nm); |
111 | } |
112 | |
113 | int ossl_cmp_hdr_update_messageTime(OSSL_CMP_PKIHEADER *hdr) |
114 | { |
115 | if (!ossl_assert(hdr != NULL)) |
116 | return 0; |
117 | if (hdr->messageTime == NULL |
118 | && (hdr->messageTime = ASN1_GENERALIZEDTIME_new()) == NULL) |
119 | return 0; |
120 | return ASN1_GENERALIZEDTIME_set(hdr->messageTime, time(NULL)) != NULL; |
121 | } |
122 | |
123 | /* assign to *tgt a copy of src (or if NULL a random byte array of given len) */ |
124 | static int set1_aostr_else_random(ASN1_OCTET_STRING **tgt, |
125 | const ASN1_OCTET_STRING *src, size_t len) |
126 | { |
127 | unsigned char *bytes = NULL; |
128 | int res = 0; |
129 | |
130 | if (src == NULL) { /* generate a random value if src == NULL */ |
131 | if ((bytes = OPENSSL_malloc(len)) == NULL) |
132 | goto err; |
133 | if (RAND_bytes(bytes, len) <= 0) { |
134 | CMPerr(0, CMP_R_FAILURE_OBTAINING_RANDOM); |
135 | goto err; |
136 | } |
137 | res = ossl_cmp_asn1_octet_string_set1_bytes(tgt, bytes, len); |
138 | } else { |
139 | res = ossl_cmp_asn1_octet_string_set1(tgt, src); |
140 | } |
141 | |
142 | err: |
143 | OPENSSL_free(bytes); |
144 | return res; |
145 | } |
146 | |
147 | int ossl_cmp_hdr_set1_senderKID(OSSL_CMP_PKIHEADER *hdr, |
148 | const ASN1_OCTET_STRING *senderKID) |
149 | { |
150 | if (!ossl_assert(hdr != NULL)) |
151 | return 0; |
152 | return ossl_cmp_asn1_octet_string_set1(&hdr->senderKID, senderKID); |
153 | } |
154 | |
155 | /* push the given text string to the given PKIFREETEXT ft */ |
156 | int ossl_cmp_pkifreetext_push_str(OSSL_CMP_PKIFREETEXT *ft, const char *text) |
157 | { |
158 | ASN1_UTF8STRING *utf8string; |
159 | |
160 | if (!ossl_assert(ft != NULL && text != NULL)) |
161 | return 0; |
162 | if ((utf8string = ASN1_UTF8STRING_new()) == NULL) |
163 | return 0; |
164 | if (!ASN1_STRING_set(utf8string, text, -1)) |
165 | goto err; |
166 | if (!sk_ASN1_UTF8STRING_push(ft, utf8string)) |
167 | goto err; |
168 | return 1; |
169 | |
170 | err: |
171 | ASN1_UTF8STRING_free(utf8string); |
172 | return 0; |
173 | } |
174 | |
175 | int ossl_cmp_hdr_push0_freeText(OSSL_CMP_PKIHEADER *hdr, ASN1_UTF8STRING *text) |
176 | { |
177 | if (!ossl_assert(hdr != NULL && text != NULL)) |
178 | return 0; |
179 | |
180 | if (hdr->freeText == NULL |
181 | && (hdr->freeText = sk_ASN1_UTF8STRING_new_null()) == NULL) |
182 | return 0; |
183 | |
184 | return sk_ASN1_UTF8STRING_push(hdr->freeText, text); |
185 | } |
186 | |
187 | int ossl_cmp_hdr_push1_freeText(OSSL_CMP_PKIHEADER *hdr, ASN1_UTF8STRING *text) |
188 | { |
189 | if (!ossl_assert(hdr != NULL && text != NULL)) |
190 | return 0; |
191 | |
192 | if (hdr->freeText == NULL |
193 | && (hdr->freeText = sk_ASN1_UTF8STRING_new_null()) == NULL) |
194 | return 0; |
195 | |
196 | return ossl_cmp_pkifreetext_push_str(hdr->freeText, (char *)text->data); |
197 | } |
198 | |
199 | int ossl_cmp_hdr_generalInfo_push0_item(OSSL_CMP_PKIHEADER *hdr, |
200 | OSSL_CMP_ITAV *itav) |
201 | { |
202 | if (!ossl_assert(hdr != NULL && itav != NULL)) |
203 | return 0; |
204 | return OSSL_CMP_ITAV_push0_stack_item(&hdr->generalInfo, itav); |
205 | } |
206 | |
207 | int ossl_cmp_hdr_generalInfo_push1_items(OSSL_CMP_PKIHEADER *hdr, |
208 | STACK_OF(OSSL_CMP_ITAV) *itavs) |
209 | { |
210 | int i; |
211 | OSSL_CMP_ITAV *itav; |
212 | |
213 | if (!ossl_assert(hdr != NULL)) |
214 | return 0; |
215 | |
216 | for (i = 0; i < sk_OSSL_CMP_ITAV_num(itavs); i++) { |
217 | itav = OSSL_CMP_ITAV_dup(sk_OSSL_CMP_ITAV_value(itavs, i)); |
218 | if (itav == NULL) |
219 | return 0; |
220 | |
221 | if (!ossl_cmp_hdr_generalInfo_push0_item(hdr, itav)) { |
222 | OSSL_CMP_ITAV_free(itav); |
223 | return 0; |
224 | } |
225 | } |
226 | return 1; |
227 | } |
228 | |
229 | int ossl_cmp_hdr_set_implicitConfirm(OSSL_CMP_PKIHEADER *hdr) |
230 | { |
231 | OSSL_CMP_ITAV *itav; |
232 | ASN1_TYPE *asn1null; |
233 | |
234 | if (!ossl_assert(hdr != NULL)) |
235 | return 0; |
236 | asn1null = (ASN1_TYPE *)ASN1_NULL_new(); |
237 | if (asn1null == NULL) |
238 | return 0; |
239 | if ((itav = OSSL_CMP_ITAV_create(OBJ_nid2obj(NID_id_it_implicitConfirm), |
240 | asn1null)) == NULL) |
241 | goto err; |
242 | if (!ossl_cmp_hdr_generalInfo_push0_item(hdr, itav)) |
243 | goto err; |
244 | return 1; |
245 | |
246 | err: |
247 | ASN1_TYPE_free(asn1null); |
248 | OSSL_CMP_ITAV_free(itav); |
249 | return 0; |
250 | } |
251 | |
252 | /* return 1 if implicitConfirm in the generalInfo field of the header is set */ |
253 | int ossl_cmp_hdr_check_implicitConfirm(const OSSL_CMP_PKIHEADER *hdr) |
254 | { |
255 | int itavCount; |
256 | int i; |
257 | OSSL_CMP_ITAV *itav; |
258 | |
259 | if (!ossl_assert(hdr != NULL)) |
260 | return 0; |
261 | |
262 | itavCount = sk_OSSL_CMP_ITAV_num(hdr->generalInfo); |
263 | for (i = 0; i < itavCount; i++) { |
264 | itav = sk_OSSL_CMP_ITAV_value(hdr->generalInfo, i); |
265 | if (itav != NULL |
266 | && OBJ_obj2nid(itav->infoType) == NID_id_it_implicitConfirm) |
267 | return 1; |
268 | } |
269 | |
270 | return 0; |
271 | } |
272 | |
273 | /* fill in all fields of the hdr according to the info given in ctx */ |
274 | int ossl_cmp_hdr_init(OSSL_CMP_CTX *ctx, OSSL_CMP_PKIHEADER *hdr) |
275 | { |
276 | X509_NAME *sender; |
277 | X509_NAME *rcp = NULL; |
278 | |
279 | if (!ossl_assert(ctx != NULL && hdr != NULL)) |
280 | return 0; |
281 | |
282 | /* set the CMP version */ |
283 | if (!ossl_cmp_hdr_set_pvno(hdr, OSSL_CMP_PVNO)) |
284 | return 0; |
285 | |
286 | sender = ctx->clCert != NULL ? |
287 | X509_get_subject_name(ctx->clCert) : ctx->subjectName; |
288 | /* |
289 | * The sender name is copied from the subject of the client cert, if any, |
290 | * or else from the the subject name provided for certification requests. |
291 | * As required by RFC 4210 section 5.1.1., if the sender name is not known |
292 | * to the client it set to NULL-DN. In this case for identification at least |
293 | * the senderKID must be set, which we take from any referenceValue given. |
294 | */ |
295 | if (sender == NULL && ctx->referenceValue == NULL) { |
296 | CMPerr(0, CMP_R_MISSING_SENDER_IDENTIFICATION); |
297 | return 0; |
298 | } |
299 | if (!ossl_cmp_hdr_set1_sender(hdr, sender)) |
300 | return 0; |
301 | |
302 | /* determine recipient entry in PKIHeader */ |
303 | if (ctx->srvCert != NULL) { |
304 | rcp = X509_get_subject_name(ctx->srvCert); |
305 | /* set also as expected_sender of responses unless set explicitly */ |
306 | if (ctx->expected_sender == NULL && rcp != NULL |
307 | && !OSSL_CMP_CTX_set1_expected_sender(ctx, rcp)) |
308 | return 0; |
309 | } else if (ctx->recipient != NULL) { |
310 | rcp = ctx->recipient; |
311 | } else if (ctx->issuer != NULL) { |
312 | rcp = ctx->issuer; |
313 | } else if (ctx->oldCert != NULL) { |
314 | rcp = X509_get_issuer_name(ctx->oldCert); |
315 | } else if (ctx->clCert != NULL) { |
316 | rcp = X509_get_issuer_name(ctx->clCert); |
317 | } |
318 | if (!ossl_cmp_hdr_set1_recipient(hdr, rcp)) |
319 | return 0; |
320 | |
321 | /* set current time as message time */ |
322 | if (!ossl_cmp_hdr_update_messageTime(hdr)) |
323 | return 0; |
324 | |
325 | if (ctx->recipNonce != NULL |
326 | && !ossl_cmp_asn1_octet_string_set1(&hdr->recipNonce, |
327 | ctx->recipNonce)) |
328 | return 0; |
329 | |
330 | /* |
331 | * set ctx->transactionID in CMP header |
332 | * if ctx->transactionID is NULL, a random one is created with 128 bit |
333 | * according to section 5.1.1: |
334 | * |
335 | * It is RECOMMENDED that the clients fill the transactionID field with |
336 | * 128 bits of (pseudo-) random data for the start of a transaction to |
337 | * reduce the probability of having the transactionID in use at the server. |
338 | */ |
339 | if (ctx->transactionID == NULL |
340 | && !set1_aostr_else_random(&ctx->transactionID, NULL, |
341 | OSSL_CMP_TRANSACTIONID_LENGTH)) |
342 | return 0; |
343 | if (!ossl_cmp_asn1_octet_string_set1(&hdr->transactionID, |
344 | ctx->transactionID)) |
345 | return 0; |
346 | |
347 | /*- |
348 | * set random senderNonce |
349 | * according to section 5.1.1: |
350 | * |
351 | * senderNonce present |
352 | * -- 128 (pseudo-)random bits |
353 | * The senderNonce and recipNonce fields protect the PKIMessage against |
354 | * replay attacks. The senderNonce will typically be 128 bits of |
355 | * (pseudo-) random data generated by the sender, whereas the recipNonce |
356 | * is copied from the senderNonce of the previous message in the |
357 | * transaction. |
358 | */ |
359 | if (!set1_aostr_else_random(&hdr->senderNonce, NULL, |
360 | OSSL_CMP_SENDERNONCE_LENGTH)) |
361 | return 0; |
362 | |
363 | /* store senderNonce - for cmp with recipNonce in next outgoing msg */ |
364 | if (!OSSL_CMP_CTX_set1_senderNonce(ctx, hdr->senderNonce)) |
365 | return 0; |
366 | |
367 | /*- |
368 | * freeText [7] PKIFreeText OPTIONAL, |
369 | * -- this may be used to indicate context-specific instructions |
370 | * -- (this field is intended for human consumption) |
371 | */ |
372 | if (ctx->freeText != NULL |
373 | && !ossl_cmp_hdr_push1_freeText(hdr, ctx->freeText)) |
374 | return 0; |
375 | |
376 | return 1; |
377 | } |
378 | |