add OSSL_STACK_OF_X509_free() for commonly used pattern
[openssl.git] / apps / lib / cmp_mock_srv.c
1 /*
2  * Copyright 2018-2021 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 *certOut;             /* certificate to be returned in cp/ip/kup msg */
22     STACK_OF(X509) *chainOut;  /* chain of certOut to add to extraCerts field */
23     STACK_OF(X509) *caPubsOut; /* certs to return in caPubs field of ip msg */
24     OSSL_CMP_PKISI *statusOut; /* status for ip/cp/kup/rp msg unless polling */
25     int sendError;             /* send error response also on valid requests */
26     OSSL_CMP_MSG *certReq;     /* ir/cr/p10cr/kur remembered while polling */
27     int certReqId;             /* id of last ir/cr/kur, used for polling */
28     int pollCount;             /* number of polls before actual cert response */
29     int curr_pollCount;        /* number of polls so far for current request */
30     int checkAfterTime;        /* time the client should wait between polling */
31 } mock_srv_ctx;
32
33
34 static void mock_srv_ctx_free(mock_srv_ctx *ctx)
35 {
36     if (ctx == NULL)
37         return;
38
39     OSSL_CMP_PKISI_free(ctx->statusOut);
40     X509_free(ctx->certOut);
41     OSSL_STACK_OF_X509_free(ctx->chainOut);
42     OSSL_STACK_OF_X509_free(ctx->caPubsOut);
43     OSSL_CMP_MSG_free(ctx->certReq);
44     OPENSSL_free(ctx);
45 }
46
47 static mock_srv_ctx *mock_srv_ctx_new(void)
48 {
49     mock_srv_ctx *ctx = OPENSSL_zalloc(sizeof(mock_srv_ctx));
50
51     if (ctx == NULL)
52         goto err;
53
54     if ((ctx->statusOut = OSSL_CMP_PKISI_new()) == NULL)
55         goto err;
56
57     ctx->certReqId = -1;
58
59     /* all other elements are initialized to 0 or NULL, respectively */
60     return ctx;
61  err:
62     mock_srv_ctx_free(ctx);
63     return NULL;
64 }
65
66 int ossl_cmp_mock_srv_set1_certOut(OSSL_CMP_SRV_CTX *srv_ctx, X509 *cert)
67 {
68     mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx);
69
70     if (ctx == NULL) {
71         ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT);
72         return 0;
73     }
74     if (cert == NULL || X509_up_ref(cert)) {
75         X509_free(ctx->certOut);
76         ctx->certOut = cert;
77         return 1;
78     }
79     return 0;
80 }
81
82 int ossl_cmp_mock_srv_set1_chainOut(OSSL_CMP_SRV_CTX *srv_ctx,
83                                     STACK_OF(X509) *chain)
84 {
85     mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx);
86     STACK_OF(X509) *chain_copy = NULL;
87
88     if (ctx == NULL) {
89         ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT);
90         return 0;
91     }
92     if (chain != NULL && (chain_copy = X509_chain_up_ref(chain)) == NULL)
93         return 0;
94     OSSL_STACK_OF_X509_free(ctx->chainOut);
95     ctx->chainOut = chain_copy;
96     return 1;
97 }
98
99 int ossl_cmp_mock_srv_set1_caPubsOut(OSSL_CMP_SRV_CTX *srv_ctx,
100                                      STACK_OF(X509) *caPubs)
101 {
102     mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx);
103     STACK_OF(X509) *caPubs_copy = NULL;
104
105     if (ctx == NULL) {
106         ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT);
107         return 0;
108     }
109     if (caPubs != NULL && (caPubs_copy = X509_chain_up_ref(caPubs)) == NULL)
110         return 0;
111     OSSL_STACK_OF_X509_free(ctx->caPubsOut);
112     ctx->caPubsOut = caPubs_copy;
113     return 1;
114 }
115
116 int ossl_cmp_mock_srv_set_statusInfo(OSSL_CMP_SRV_CTX *srv_ctx, int status,
117                                      int fail_info, const char *text)
118 {
119     mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx);
120     OSSL_CMP_PKISI *si;
121
122     if (ctx == NULL) {
123         ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT);
124         return 0;
125     }
126     if ((si = OSSL_CMP_STATUSINFO_new(status, fail_info, text)) == NULL)
127         return 0;
128     OSSL_CMP_PKISI_free(ctx->statusOut);
129     ctx->statusOut = si;
130     return 1;
131 }
132
133 int ossl_cmp_mock_srv_set_send_error(OSSL_CMP_SRV_CTX *srv_ctx, int val)
134 {
135     mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx);
136
137     if (ctx == NULL) {
138         ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT);
139         return 0;
140     }
141     ctx->sendError = val != 0;
142     return 1;
143 }
144
145 int ossl_cmp_mock_srv_set_pollCount(OSSL_CMP_SRV_CTX *srv_ctx, int count)
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     if (count < 0) {
154         ERR_raise(ERR_LIB_CMP, CMP_R_INVALID_ARGS);
155         return 0;
156     }
157     ctx->pollCount = count;
158     return 1;
159 }
160
161 int ossl_cmp_mock_srv_set_checkAfterTime(OSSL_CMP_SRV_CTX *srv_ctx, int sec)
162 {
163     mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx);
164
165     if (ctx == NULL) {
166         ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT);
167         return 0;
168     }
169     ctx->checkAfterTime = sec;
170     return 1;
171 }
172
173 static OSSL_CMP_PKISI *process_cert_request(OSSL_CMP_SRV_CTX *srv_ctx,
174                                             const OSSL_CMP_MSG *cert_req,
175                                             int certReqId,
176                                             const OSSL_CRMF_MSG *crm,
177                                             const X509_REQ *p10cr,
178                                             X509 **certOut,
179                                             STACK_OF(X509) **chainOut,
180                                             STACK_OF(X509) **caPubs)
181 {
182     mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx);
183     OSSL_CMP_PKISI *si = NULL;
184
185     if (ctx == NULL || cert_req == NULL
186             || certOut == NULL || chainOut == NULL || caPubs == NULL) {
187         ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT);
188         return NULL;
189     }
190     if (ctx->sendError) {
191         ERR_raise(ERR_LIB_CMP, CMP_R_ERROR_PROCESSING_MESSAGE);
192         return NULL;
193     }
194
195     *certOut = NULL;
196     *chainOut = NULL;
197     *caPubs = NULL;
198     ctx->certReqId = certReqId;
199
200     if (ctx->pollCount > 0 && ctx->curr_pollCount == 0) {
201         /* start polling */
202         if (ctx->certReq != NULL) {
203             /* already in polling mode */
204             ERR_raise(ERR_LIB_CMP, CMP_R_UNEXPECTED_PKIBODY);
205             return NULL;
206         }
207         if ((ctx->certReq = OSSL_CMP_MSG_dup(cert_req)) == NULL)
208             return NULL;
209         return OSSL_CMP_STATUSINFO_new(OSSL_CMP_PKISTATUS_waiting, 0, NULL);
210     }
211     if (ctx->curr_pollCount >= ctx->pollCount)
212         /* give final response after polling */
213         ctx->curr_pollCount = 0;
214
215     if (OSSL_CMP_MSG_get_bodytype(cert_req) == OSSL_CMP_KUR
216             && crm != NULL && ctx->certOut != NULL) {
217         const OSSL_CRMF_CERTID *cid = OSSL_CRMF_MSG_get0_regCtrl_oldCertID(crm);
218         const X509_NAME *issuer = X509_get_issuer_name(ctx->certOut);
219         const ASN1_INTEGER *serial = X509_get0_serialNumber(ctx->certOut);
220
221         if (cid == NULL) {
222             ERR_raise(ERR_LIB_CMP, CMP_R_MISSING_CERTID);
223             return NULL;
224         }
225         if (issuer != NULL
226             && X509_NAME_cmp(issuer, OSSL_CRMF_CERTID_get0_issuer(cid)) != 0) {
227             ERR_raise(ERR_LIB_CMP, CMP_R_WRONG_CERTID);
228             return NULL;
229         }
230         if (serial != NULL
231             && ASN1_INTEGER_cmp(serial,
232                                 OSSL_CRMF_CERTID_get0_serialNumber(cid)) != 0) {
233             ERR_raise(ERR_LIB_CMP, CMP_R_WRONG_CERTID);
234             return NULL;
235         }
236     }
237
238     if (ctx->certOut != NULL
239             && (*certOut = X509_dup(ctx->certOut)) == NULL)
240         goto err;
241     if (ctx->chainOut != NULL
242             && (*chainOut = X509_chain_up_ref(ctx->chainOut)) == NULL)
243         goto err;
244     if (ctx->caPubsOut != NULL
245             && (*caPubs = X509_chain_up_ref(ctx->caPubsOut)) == NULL)
246         goto err;
247     if (ctx->statusOut != NULL
248             && (si = OSSL_CMP_PKISI_dup(ctx->statusOut)) == NULL)
249         goto err;
250     return si;
251
252  err:
253     X509_free(*certOut);
254     *certOut = NULL;
255     OSSL_STACK_OF_X509_free(*chainOut);
256     *chainOut = NULL;
257     OSSL_STACK_OF_X509_free(*caPubs);
258     *caPubs = NULL;
259     return NULL;
260 }
261
262 static OSSL_CMP_PKISI *process_rr(OSSL_CMP_SRV_CTX *srv_ctx,
263                                   const OSSL_CMP_MSG *rr,
264                                   const X509_NAME *issuer,
265                                   const ASN1_INTEGER *serial)
266 {
267     mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx);
268
269     if (ctx == NULL || rr == NULL) {
270         ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT);
271         return NULL;
272     }
273     if (ctx->sendError || ctx->certOut == NULL) {
274         ERR_raise(ERR_LIB_CMP, CMP_R_ERROR_PROCESSING_MESSAGE);
275         return NULL;
276     }
277
278     /* Allow any RR derived from CSR, which may include subject and serial */
279     if (issuer == NULL || serial == NULL)
280         return OSSL_CMP_PKISI_dup(ctx->statusOut);
281
282     /* accept revocation only for the certificate we sent in ir/cr/kur */
283     if (X509_NAME_cmp(issuer, X509_get_issuer_name(ctx->certOut)) != 0
284             || ASN1_INTEGER_cmp(serial,
285                                 X509_get0_serialNumber(ctx->certOut)) != 0) {
286         ERR_raise_data(ERR_LIB_CMP, CMP_R_REQUEST_NOT_ACCEPTED,
287                        "wrong certificate to revoke");
288         return NULL;
289     }
290     return OSSL_CMP_PKISI_dup(ctx->statusOut);
291 }
292
293 static int process_genm(OSSL_CMP_SRV_CTX *srv_ctx,
294                         const OSSL_CMP_MSG *genm,
295                         const STACK_OF(OSSL_CMP_ITAV) *in,
296                         STACK_OF(OSSL_CMP_ITAV) **out)
297 {
298     mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx);
299
300     if (ctx == NULL || genm == NULL || in == NULL || out == NULL) {
301         ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT);
302         return 0;
303     }
304     if (ctx->sendError) {
305         ERR_raise(ERR_LIB_CMP, CMP_R_ERROR_PROCESSING_MESSAGE);
306         return 0;
307     }
308
309     *out = sk_OSSL_CMP_ITAV_deep_copy(in, OSSL_CMP_ITAV_dup,
310                                       OSSL_CMP_ITAV_free);
311     return *out != NULL;
312 }
313
314 static void process_error(OSSL_CMP_SRV_CTX *srv_ctx, const OSSL_CMP_MSG *error,
315                           const OSSL_CMP_PKISI *statusInfo,
316                           const ASN1_INTEGER *errorCode,
317                           const OSSL_CMP_PKIFREETEXT *errorDetails)
318 {
319     mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx);
320     char buf[OSSL_CMP_PKISI_BUFLEN];
321     char *sibuf;
322     int i;
323
324     if (ctx == NULL || error == NULL) {
325         ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT);
326         return;
327     }
328
329     BIO_printf(bio_err, "mock server received error:\n");
330
331     if (statusInfo == NULL) {
332         BIO_printf(bio_err, "pkiStatusInfo absent\n");
333     } else {
334         sibuf = OSSL_CMP_snprint_PKIStatusInfo(statusInfo, buf, sizeof(buf));
335         BIO_printf(bio_err, "pkiStatusInfo: %s\n",
336                    sibuf != NULL ? sibuf: "<invalid>");
337     }
338
339     if (errorCode == NULL)
340         BIO_printf(bio_err, "errorCode absent\n");
341     else
342         BIO_printf(bio_err, "errorCode: %ld\n", ASN1_INTEGER_get(errorCode));
343
344     if (sk_ASN1_UTF8STRING_num(errorDetails) <= 0) {
345         BIO_printf(bio_err, "errorDetails absent\n");
346     } else {
347         BIO_printf(bio_err, "errorDetails: ");
348         for (i = 0; i < sk_ASN1_UTF8STRING_num(errorDetails); i++) {
349             if (i > 0)
350                 BIO_printf(bio_err, ", ");
351             BIO_printf(bio_err, "\"");
352             ASN1_STRING_print(bio_err,
353                               sk_ASN1_UTF8STRING_value(errorDetails, i));
354             BIO_printf(bio_err, "\"");
355         }
356         BIO_printf(bio_err, "\n");
357     }
358 }
359
360 static int process_certConf(OSSL_CMP_SRV_CTX *srv_ctx,
361                             const OSSL_CMP_MSG *certConf, int certReqId,
362                             const ASN1_OCTET_STRING *certHash,
363                             const OSSL_CMP_PKISI *si)
364 {
365     mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx);
366     ASN1_OCTET_STRING *digest;
367
368     if (ctx == NULL || certConf == NULL || certHash == NULL) {
369         ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT);
370         return 0;
371     }
372     if (ctx->sendError || ctx->certOut == NULL) {
373         ERR_raise(ERR_LIB_CMP, CMP_R_ERROR_PROCESSING_MESSAGE);
374         return 0;
375     }
376
377     if (certReqId != ctx->certReqId) {
378         /* in case of error, invalid reqId -1 */
379         ERR_raise(ERR_LIB_CMP, CMP_R_BAD_REQUEST_ID);
380         return 0;
381     }
382
383     if ((digest = X509_digest_sig(ctx->certOut, NULL, NULL)) == NULL)
384         return 0;
385     if (ASN1_OCTET_STRING_cmp(certHash, digest) != 0) {
386         ASN1_OCTET_STRING_free(digest);
387         ERR_raise(ERR_LIB_CMP, CMP_R_CERTHASH_UNMATCHED);
388         return 0;
389     }
390     ASN1_OCTET_STRING_free(digest);
391     return 1;
392 }
393
394 static int process_pollReq(OSSL_CMP_SRV_CTX *srv_ctx,
395                            const OSSL_CMP_MSG *pollReq, int certReqId,
396                            OSSL_CMP_MSG **certReq, int64_t *check_after)
397 {
398     mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx);
399
400     if (ctx == NULL || pollReq == NULL
401             || certReq == NULL || check_after == NULL) {
402         ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT);
403         return 0;
404     }
405     if (ctx->sendError) {
406         *certReq = NULL;
407         ERR_raise(ERR_LIB_CMP, CMP_R_ERROR_PROCESSING_MESSAGE);
408         return 0;
409     }
410     if (ctx->certReq == NULL) {
411         /* not currently in polling mode */
412         *certReq = NULL;
413         ERR_raise(ERR_LIB_CMP, CMP_R_UNEXPECTED_PKIBODY);
414         return 0;
415     }
416
417     if (++ctx->curr_pollCount >= ctx->pollCount) {
418         /* end polling */
419         *certReq = ctx->certReq;
420         ctx->certReq = NULL;
421         *check_after = 0;
422     } else {
423         *certReq = NULL;
424         *check_after = ctx->checkAfterTime;
425     }
426     return 1;
427 }
428
429 OSSL_CMP_SRV_CTX *ossl_cmp_mock_srv_new(OSSL_LIB_CTX *libctx, const char *propq)
430 {
431     OSSL_CMP_SRV_CTX *srv_ctx = OSSL_CMP_SRV_CTX_new(libctx, propq);
432     mock_srv_ctx *ctx = mock_srv_ctx_new();
433
434     if (srv_ctx != NULL && ctx != NULL
435             && OSSL_CMP_SRV_CTX_init(srv_ctx, ctx, process_cert_request,
436                                      process_rr, process_genm, process_error,
437                                      process_certConf, process_pollReq))
438         return srv_ctx;
439
440     mock_srv_ctx_free(ctx);
441     OSSL_CMP_SRV_CTX_free(srv_ctx);
442     return NULL;
443 }
444
445 void ossl_cmp_mock_srv_free(OSSL_CMP_SRV_CTX *srv_ctx)
446 {
447     if (srv_ctx != NULL)
448         mock_srv_ctx_free(OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx));
449     OSSL_CMP_SRV_CTX_free(srv_ctx);
450 }