]> git.ipfire.org Git - thirdparty/openssl.git/blob - apps/lib/cmp_mock_srv.c
a0450446c1ca631cbe25d8879374a1dfb91ea441
[thirdparty/openssl.git] / apps / lib / cmp_mock_srv.c
1 /*
2 * Copyright 2018-2023 The OpenSSL Project Authors. All Rights Reserved.
3 * Copyright Siemens AG 2018-2020
4 *
5 * Licensed under the Apache License 2.0 (the "License"). You may not use
6 * this file except in compliance with the License. You can obtain a copy
7 * in the file LICENSE in the source distribution or atf
8 * https://www.openssl.org/source/license.html
9 */
10
11 #include "apps.h"
12 #include "cmp_mock_srv.h"
13
14 #include <openssl/cmp.h>
15 #include <openssl/err.h>
16 #include <openssl/cmperr.h>
17
18 /* the context for the CMP mock server */
19 typedef struct
20 {
21 X509 *refCert; /* cert to expect for oldCertID in kur/rr msg */
22 X509 *certOut; /* certificate to be returned in cp/ip/kup msg */
23 STACK_OF(X509) *chainOut; /* chain of certOut to add to extraCerts field */
24 STACK_OF(X509) *caPubsOut; /* used in caPubs of ip and in caCerts of genp */
25 X509 *newWithNew; /* to return in newWithNew of rootKeyUpdate */
26 X509 *newWithOld; /* to return in newWithOld of rootKeyUpdate */
27 X509 *oldWithNew; /* to return in oldWithNew of rootKeyUpdate */
28 OSSL_CMP_PKISI *statusOut; /* status for ip/cp/kup/rp msg unless polling */
29 int sendError; /* send error response on given request type */
30 OSSL_CMP_MSG *certReq; /* ir/cr/p10cr/kur remembered while polling */
31 int pollCount; /* number of polls before actual cert response */
32 int curr_pollCount; /* number of polls so far for current request */
33 int checkAfterTime; /* time the client should wait between polling */
34 } mock_srv_ctx;
35
36 static void mock_srv_ctx_free(mock_srv_ctx *ctx)
37 {
38 if (ctx == NULL)
39 return;
40
41 OSSL_CMP_PKISI_free(ctx->statusOut);
42 X509_free(ctx->refCert);
43 X509_free(ctx->certOut);
44 OSSL_STACK_OF_X509_free(ctx->chainOut);
45 OSSL_STACK_OF_X509_free(ctx->caPubsOut);
46 OSSL_CMP_MSG_free(ctx->certReq);
47 OPENSSL_free(ctx);
48 }
49
50 static mock_srv_ctx *mock_srv_ctx_new(void)
51 {
52 mock_srv_ctx *ctx = OPENSSL_zalloc(sizeof(mock_srv_ctx));
53
54 if (ctx == NULL)
55 goto err;
56
57 if ((ctx->statusOut = OSSL_CMP_PKISI_new()) == NULL)
58 goto err;
59
60 ctx->sendError = -1;
61
62 /* all other elements are initialized to 0 or NULL, respectively */
63 return ctx;
64 err:
65 mock_srv_ctx_free(ctx);
66 return NULL;
67 }
68
69 #define DEFINE_OSSL_SET1_CERT(FIELD) \
70 int ossl_cmp_mock_srv_set1_##FIELD(OSSL_CMP_SRV_CTX *srv_ctx, \
71 X509 *cert) \
72 { \
73 mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx); \
74 \
75 if (ctx == NULL) { \
76 ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); \
77 return 0; \
78 } \
79 if (cert == NULL || X509_up_ref(cert)) { \
80 X509_free(ctx->FIELD); \
81 ctx->FIELD = cert; \
82 return 1; \
83 } \
84 return 0; \
85 }
86
87 DEFINE_OSSL_SET1_CERT(refCert)
88 DEFINE_OSSL_SET1_CERT(certOut)
89
90 int ossl_cmp_mock_srv_set1_chainOut(OSSL_CMP_SRV_CTX *srv_ctx,
91 STACK_OF(X509) *chain)
92 {
93 mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx);
94 STACK_OF(X509) *chain_copy = NULL;
95
96 if (ctx == NULL) {
97 ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT);
98 return 0;
99 }
100 if (chain != NULL && (chain_copy = X509_chain_up_ref(chain)) == NULL)
101 return 0;
102 OSSL_STACK_OF_X509_free(ctx->chainOut);
103 ctx->chainOut = chain_copy;
104 return 1;
105 }
106
107 int ossl_cmp_mock_srv_set1_caPubsOut(OSSL_CMP_SRV_CTX *srv_ctx,
108 STACK_OF(X509) *caPubs)
109 {
110 mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx);
111 STACK_OF(X509) *caPubs_copy = NULL;
112
113 if (ctx == NULL) {
114 ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT);
115 return 0;
116 }
117 if (caPubs != NULL && (caPubs_copy = X509_chain_up_ref(caPubs)) == NULL)
118 return 0;
119 OSSL_STACK_OF_X509_free(ctx->caPubsOut);
120 ctx->caPubsOut = caPubs_copy;
121 return 1;
122 }
123
124 DEFINE_OSSL_SET1_CERT(newWithNew)
125 DEFINE_OSSL_SET1_CERT(newWithOld)
126 DEFINE_OSSL_SET1_CERT(oldWithNew)
127
128 int ossl_cmp_mock_srv_set_statusInfo(OSSL_CMP_SRV_CTX *srv_ctx, int status,
129 int fail_info, const char *text)
130 {
131 mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx);
132 OSSL_CMP_PKISI *si;
133
134 if (ctx == NULL) {
135 ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT);
136 return 0;
137 }
138 if ((si = OSSL_CMP_STATUSINFO_new(status, fail_info, text)) == NULL)
139 return 0;
140 OSSL_CMP_PKISI_free(ctx->statusOut);
141 ctx->statusOut = si;
142 return 1;
143 }
144
145 int ossl_cmp_mock_srv_set_sendError(OSSL_CMP_SRV_CTX *srv_ctx, int bodytype)
146 {
147 mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx);
148
149 if (ctx == NULL) {
150 ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT);
151 return 0;
152 }
153 /* might check bodytype, but this would require exporting all body types */
154 ctx->sendError = bodytype;
155 return 1;
156 }
157
158 int ossl_cmp_mock_srv_set_pollCount(OSSL_CMP_SRV_CTX *srv_ctx, int count)
159 {
160 mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx);
161
162 if (ctx == NULL) {
163 ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT);
164 return 0;
165 }
166 if (count < 0) {
167 ERR_raise(ERR_LIB_CMP, CMP_R_INVALID_ARGS);
168 return 0;
169 }
170 ctx->pollCount = count;
171 return 1;
172 }
173
174 int ossl_cmp_mock_srv_set_checkAfterTime(OSSL_CMP_SRV_CTX *srv_ctx, int sec)
175 {
176 mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx);
177
178 if (ctx == NULL) {
179 ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT);
180 return 0;
181 }
182 ctx->checkAfterTime = sec;
183 return 1;
184 }
185
186 /* check for matching reference cert components, as far as given */
187 static int refcert_cmp(const X509 *refcert,
188 const X509_NAME *issuer, const ASN1_INTEGER *serial)
189 {
190 const X509_NAME *ref_issuer;
191 const ASN1_INTEGER *ref_serial;
192
193 if (refcert == NULL)
194 return 1;
195 ref_issuer = X509_get_issuer_name(refcert);
196 ref_serial = X509_get0_serialNumber(refcert);
197 return (ref_issuer == NULL || X509_NAME_cmp(issuer, ref_issuer) == 0)
198 && (ref_serial == NULL || ASN1_INTEGER_cmp(serial, ref_serial) == 0);
199 }
200
201 static OSSL_CMP_PKISI *process_cert_request(OSSL_CMP_SRV_CTX *srv_ctx,
202 const OSSL_CMP_MSG *cert_req,
203 ossl_unused int certReqId,
204 const OSSL_CRMF_MSG *crm,
205 const X509_REQ *p10cr,
206 X509 **certOut,
207 STACK_OF(X509) **chainOut,
208 STACK_OF(X509) **caPubs)
209 {
210 mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx);
211 int bodytype;
212 OSSL_CMP_PKISI *si = NULL;
213
214 if (ctx == NULL || cert_req == NULL
215 || certOut == NULL || chainOut == NULL || caPubs == NULL) {
216 ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT);
217 return NULL;
218 }
219 bodytype = OSSL_CMP_MSG_get_bodytype(cert_req);
220 if (ctx->sendError == 1 || ctx->sendError == bodytype) {
221 ERR_raise(ERR_LIB_CMP, CMP_R_ERROR_PROCESSING_MESSAGE);
222 return NULL;
223 }
224
225 *certOut = NULL;
226 *chainOut = NULL;
227 *caPubs = NULL;
228
229 if (ctx->pollCount > 0 && ctx->curr_pollCount == 0) {
230 /* start polling */
231 if (ctx->certReq != NULL) {
232 /* already in polling mode */
233 ERR_raise(ERR_LIB_CMP, CMP_R_UNEXPECTED_PKIBODY);
234 return NULL;
235 }
236 if ((ctx->certReq = OSSL_CMP_MSG_dup(cert_req)) == NULL)
237 return NULL;
238 return OSSL_CMP_STATUSINFO_new(OSSL_CMP_PKISTATUS_waiting, 0, NULL);
239 }
240 if (ctx->curr_pollCount >= ctx->pollCount)
241 /* give final response after polling */
242 ctx->curr_pollCount = 0;
243
244 /* accept cert update request only for the reference cert, if given */
245 if (bodytype == OSSL_CMP_KUR
246 && crm != NULL /* thus not p10cr */ && ctx->refCert != NULL) {
247 const OSSL_CRMF_CERTID *cid = OSSL_CRMF_MSG_get0_regCtrl_oldCertID(crm);
248
249 if (cid == NULL) {
250 ERR_raise(ERR_LIB_CMP, CMP_R_MISSING_CERTID);
251 return NULL;
252 }
253 if (!refcert_cmp(ctx->refCert,
254 OSSL_CRMF_CERTID_get0_issuer(cid),
255 OSSL_CRMF_CERTID_get0_serialNumber(cid))) {
256 ERR_raise(ERR_LIB_CMP, CMP_R_WRONG_CERTID);
257 return NULL;
258 }
259 }
260
261 if (ctx->certOut != NULL
262 && (*certOut = X509_dup(ctx->certOut)) == NULL)
263 /* Should return a cert produced from request template, see FR #16054 */
264 goto err;
265 if (ctx->chainOut != NULL
266 && (*chainOut = X509_chain_up_ref(ctx->chainOut)) == NULL)
267 goto err;
268 if (ctx->caPubsOut != NULL /* OSSL_CMP_PKIBODY_IP not visible here */
269 && (*caPubs = X509_chain_up_ref(ctx->caPubsOut)) == NULL)
270 goto err;
271 if (ctx->statusOut != NULL
272 && (si = OSSL_CMP_PKISI_dup(ctx->statusOut)) == NULL)
273 goto err;
274 return si;
275
276 err:
277 X509_free(*certOut);
278 *certOut = NULL;
279 OSSL_STACK_OF_X509_free(*chainOut);
280 *chainOut = NULL;
281 OSSL_STACK_OF_X509_free(*caPubs);
282 *caPubs = NULL;
283 return NULL;
284 }
285
286 static OSSL_CMP_PKISI *process_rr(OSSL_CMP_SRV_CTX *srv_ctx,
287 const OSSL_CMP_MSG *rr,
288 const X509_NAME *issuer,
289 const ASN1_INTEGER *serial)
290 {
291 mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx);
292
293 if (ctx == NULL || rr == NULL) {
294 ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT);
295 return NULL;
296 }
297 if (ctx->sendError == 1
298 || ctx->sendError == OSSL_CMP_MSG_get_bodytype(rr)) {
299 ERR_raise(ERR_LIB_CMP, CMP_R_ERROR_PROCESSING_MESSAGE);
300 return NULL;
301 }
302
303 /* allow any RR derived from CSR which does not include issuer and serial */
304 if ((issuer != NULL || serial != NULL)
305 /* accept revocation only for the reference cert, if given */
306 && !refcert_cmp(ctx->refCert, issuer, serial)) {
307 ERR_raise_data(ERR_LIB_CMP, CMP_R_REQUEST_NOT_ACCEPTED,
308 "wrong certificate to revoke");
309 return NULL;
310 }
311 return OSSL_CMP_PKISI_dup(ctx->statusOut);
312 }
313
314 static OSSL_CMP_ITAV *process_genm_itav(mock_srv_ctx *ctx, int req_nid,
315 const OSSL_CMP_ITAV *req)
316 {
317 OSSL_CMP_ITAV *rsp;
318
319 switch (req_nid) {
320 case NID_id_it_caCerts:
321 rsp = OSSL_CMP_ITAV_new_caCerts(ctx->caPubsOut);
322 break;
323 case NID_id_it_rootCaCert:
324 rsp = OSSL_CMP_ITAV_new_rootCaKeyUpdate(ctx->newWithNew,
325 ctx->newWithOld,
326 ctx->oldWithNew);
327 break;
328 default:
329 rsp = OSSL_CMP_ITAV_dup(req);
330 }
331 return rsp;
332 }
333
334 static int process_genm(OSSL_CMP_SRV_CTX *srv_ctx,
335 const OSSL_CMP_MSG *genm,
336 const STACK_OF(OSSL_CMP_ITAV) *in,
337 STACK_OF(OSSL_CMP_ITAV) **out)
338 {
339 mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx);
340
341 if (ctx == NULL || genm == NULL || in == NULL || out == NULL) {
342 ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT);
343 return 0;
344 }
345 if (ctx->sendError == 1
346 || ctx->sendError == OSSL_CMP_MSG_get_bodytype(genm)
347 || sk_OSSL_CMP_ITAV_num(in) > 1) {
348 ERR_raise(ERR_LIB_CMP, CMP_R_ERROR_PROCESSING_MESSAGE);
349 return 0;
350 }
351 if (sk_OSSL_CMP_ITAV_num(in) == 1) {
352 OSSL_CMP_ITAV *req = sk_OSSL_CMP_ITAV_value(in, 0), *rsp;
353 ASN1_OBJECT *obj = OSSL_CMP_ITAV_get0_type(req);
354
355 if ((*out = sk_OSSL_CMP_ITAV_new_reserve(NULL, 1)) == NULL)
356 return 0;
357 rsp = process_genm_itav(ctx, OBJ_obj2nid(obj), req);
358 if (rsp != NULL && sk_OSSL_CMP_ITAV_push(*out, rsp))
359 return 1;
360 sk_OSSL_CMP_ITAV_free(*out);
361 return 0;
362 }
363
364 *out = sk_OSSL_CMP_ITAV_deep_copy(in, OSSL_CMP_ITAV_dup,
365 OSSL_CMP_ITAV_free);
366 return *out != NULL;
367 }
368
369 static void process_error(OSSL_CMP_SRV_CTX *srv_ctx, const OSSL_CMP_MSG *error,
370 const OSSL_CMP_PKISI *statusInfo,
371 const ASN1_INTEGER *errorCode,
372 const OSSL_CMP_PKIFREETEXT *errorDetails)
373 {
374 mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx);
375 char buf[OSSL_CMP_PKISI_BUFLEN];
376 char *sibuf;
377 int i;
378
379 if (ctx == NULL || error == NULL) {
380 ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT);
381 return;
382 }
383
384 BIO_printf(bio_err, "mock server received error:\n");
385
386 if (statusInfo == NULL) {
387 BIO_printf(bio_err, "pkiStatusInfo absent\n");
388 } else {
389 sibuf = OSSL_CMP_snprint_PKIStatusInfo(statusInfo, buf, sizeof(buf));
390 BIO_printf(bio_err, "pkiStatusInfo: %s\n",
391 sibuf != NULL ? sibuf: "<invalid>");
392 }
393
394 if (errorCode == NULL)
395 BIO_printf(bio_err, "errorCode absent\n");
396 else
397 BIO_printf(bio_err, "errorCode: %ld\n", ASN1_INTEGER_get(errorCode));
398
399 if (sk_ASN1_UTF8STRING_num(errorDetails) <= 0) {
400 BIO_printf(bio_err, "errorDetails absent\n");
401 } else {
402 BIO_printf(bio_err, "errorDetails: ");
403 for (i = 0; i < sk_ASN1_UTF8STRING_num(errorDetails); i++) {
404 if (i > 0)
405 BIO_printf(bio_err, ", ");
406 ASN1_STRING_print_ex(bio_err,
407 sk_ASN1_UTF8STRING_value(errorDetails, i),
408 ASN1_STRFLGS_ESC_QUOTE);
409 }
410 BIO_printf(bio_err, "\n");
411 }
412 }
413
414 static int process_certConf(OSSL_CMP_SRV_CTX *srv_ctx,
415 const OSSL_CMP_MSG *certConf,
416 ossl_unused int certReqId,
417 const ASN1_OCTET_STRING *certHash,
418 const OSSL_CMP_PKISI *si)
419 {
420 mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx);
421 ASN1_OCTET_STRING *digest;
422
423 if (ctx == NULL || certConf == NULL || certHash == NULL) {
424 ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT);
425 return 0;
426 }
427 if (ctx->sendError == 1
428 || ctx->sendError == OSSL_CMP_MSG_get_bodytype(certConf)
429 || ctx->certOut == NULL) {
430 ERR_raise(ERR_LIB_CMP, CMP_R_ERROR_PROCESSING_MESSAGE);
431 return 0;
432 }
433
434 if ((digest = X509_digest_sig(ctx->certOut, NULL, NULL)) == NULL)
435 return 0;
436 if (ASN1_OCTET_STRING_cmp(certHash, digest) != 0) {
437 ASN1_OCTET_STRING_free(digest);
438 ERR_raise(ERR_LIB_CMP, CMP_R_CERTHASH_UNMATCHED);
439 return 0;
440 }
441 ASN1_OCTET_STRING_free(digest);
442 return 1;
443 }
444
445 static int process_pollReq(OSSL_CMP_SRV_CTX *srv_ctx,
446 const OSSL_CMP_MSG *pollReq,
447 ossl_unused int certReqId,
448 OSSL_CMP_MSG **certReq, int64_t *check_after)
449 {
450 mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx);
451
452 if (ctx == NULL || pollReq == NULL
453 || certReq == NULL || check_after == NULL) {
454 ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT);
455 return 0;
456 }
457 if (ctx->sendError == 1
458 || ctx->sendError == OSSL_CMP_MSG_get_bodytype(pollReq)) {
459 *certReq = NULL;
460 ERR_raise(ERR_LIB_CMP, CMP_R_ERROR_PROCESSING_MESSAGE);
461 return 0;
462 }
463 if (ctx->certReq == NULL) {
464 /* not currently in polling mode */
465 *certReq = NULL;
466 ERR_raise(ERR_LIB_CMP, CMP_R_UNEXPECTED_PKIBODY);
467 return 0;
468 }
469
470 if (++ctx->curr_pollCount >= ctx->pollCount) {
471 /* end polling */
472 *certReq = ctx->certReq;
473 ctx->certReq = NULL;
474 *check_after = 0;
475 } else {
476 *certReq = NULL;
477 *check_after = ctx->checkAfterTime;
478 }
479 return 1;
480 }
481
482 OSSL_CMP_SRV_CTX *ossl_cmp_mock_srv_new(OSSL_LIB_CTX *libctx, const char *propq)
483 {
484 OSSL_CMP_SRV_CTX *srv_ctx = OSSL_CMP_SRV_CTX_new(libctx, propq);
485 mock_srv_ctx *ctx = mock_srv_ctx_new();
486
487 if (srv_ctx != NULL && ctx != NULL
488 && OSSL_CMP_SRV_CTX_init(srv_ctx, ctx, process_cert_request,
489 process_rr, process_genm, process_error,
490 process_certConf, process_pollReq))
491 return srv_ctx;
492
493 mock_srv_ctx_free(ctx);
494 OSSL_CMP_SRV_CTX_free(srv_ctx);
495 return NULL;
496 }
497
498 void ossl_cmp_mock_srv_free(OSSL_CMP_SRV_CTX *srv_ctx)
499 {
500 if (srv_ctx != NULL)
501 mock_srv_ctx_free(OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx));
502 OSSL_CMP_SRV_CTX_free(srv_ctx);
503 }