xref: /third_party/openssl/apps/lib/cmp_mock_srv.c (revision e1051a39)
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 */
19typedef 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 on given request type */
26    OSSL_CMP_MSG *certReq;     /* ir/cr/p10cr/kur remembered while polling */
27    int pollCount;             /* number of polls before actual cert response */
28    int curr_pollCount;        /* number of polls so far for current request */
29    int checkAfterTime;        /* time the client should wait between polling */
30} mock_srv_ctx;
31
32
33static void mock_srv_ctx_free(mock_srv_ctx *ctx)
34{
35    if (ctx == NULL)
36        return;
37
38    OSSL_CMP_PKISI_free(ctx->statusOut);
39    X509_free(ctx->certOut);
40    sk_X509_pop_free(ctx->chainOut, X509_free);
41    sk_X509_pop_free(ctx->caPubsOut, X509_free);
42    OSSL_CMP_MSG_free(ctx->certReq);
43    OPENSSL_free(ctx);
44}
45
46static mock_srv_ctx *mock_srv_ctx_new(void)
47{
48    mock_srv_ctx *ctx = OPENSSL_zalloc(sizeof(mock_srv_ctx));
49
50    if (ctx == NULL)
51        goto err;
52
53    if ((ctx->statusOut = OSSL_CMP_PKISI_new()) == NULL)
54        goto err;
55
56    ctx->sendError = -1;
57
58    /* all other elements are initialized to 0 or NULL, respectively */
59    return ctx;
60 err:
61    mock_srv_ctx_free(ctx);
62    return NULL;
63}
64
65int ossl_cmp_mock_srv_set1_certOut(OSSL_CMP_SRV_CTX *srv_ctx, X509 *cert)
66{
67    mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx);
68
69    if (ctx == NULL) {
70        ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT);
71        return 0;
72    }
73    if (cert == NULL || X509_up_ref(cert)) {
74        X509_free(ctx->certOut);
75        ctx->certOut = cert;
76        return 1;
77    }
78    return 0;
79}
80
81int ossl_cmp_mock_srv_set1_chainOut(OSSL_CMP_SRV_CTX *srv_ctx,
82                                    STACK_OF(X509) *chain)
83{
84    mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx);
85    STACK_OF(X509) *chain_copy = NULL;
86
87    if (ctx == NULL) {
88        ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT);
89        return 0;
90    }
91    if (chain != NULL && (chain_copy = X509_chain_up_ref(chain)) == NULL)
92        return 0;
93    sk_X509_pop_free(ctx->chainOut, X509_free);
94    ctx->chainOut = chain_copy;
95    return 1;
96}
97
98int ossl_cmp_mock_srv_set1_caPubsOut(OSSL_CMP_SRV_CTX *srv_ctx,
99                                     STACK_OF(X509) *caPubs)
100{
101    mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx);
102    STACK_OF(X509) *caPubs_copy = NULL;
103
104    if (ctx == NULL) {
105        ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT);
106        return 0;
107    }
108    if (caPubs != NULL && (caPubs_copy = X509_chain_up_ref(caPubs)) == NULL)
109        return 0;
110    sk_X509_pop_free(ctx->caPubsOut, X509_free);
111    ctx->caPubsOut = caPubs_copy;
112    return 1;
113}
114
115int ossl_cmp_mock_srv_set_statusInfo(OSSL_CMP_SRV_CTX *srv_ctx, int status,
116                                     int fail_info, const char *text)
117{
118    mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx);
119    OSSL_CMP_PKISI *si;
120
121    if (ctx == NULL) {
122        ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT);
123        return 0;
124    }
125    if ((si = OSSL_CMP_STATUSINFO_new(status, fail_info, text)) == NULL)
126        return 0;
127    OSSL_CMP_PKISI_free(ctx->statusOut);
128    ctx->statusOut = si;
129    return 1;
130}
131
132int ossl_cmp_mock_srv_set_sendError(OSSL_CMP_SRV_CTX *srv_ctx, int bodytype)
133{
134    mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx);
135
136    if (ctx == NULL) {
137        ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT);
138        return 0;
139    }
140    /* might check bodytype, but this would require exporting all body types */
141    ctx->sendError = bodytype;
142    return 1;
143}
144
145int 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
161int 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
173static OSSL_CMP_PKISI *process_cert_request(OSSL_CMP_SRV_CTX *srv_ctx,
174                                            const OSSL_CMP_MSG *cert_req,
175                                            ossl_unused 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 == 1
191            || ctx->sendError == OSSL_CMP_MSG_get_bodytype(cert_req)) {
192        ERR_raise(ERR_LIB_CMP, CMP_R_ERROR_PROCESSING_MESSAGE);
193        return NULL;
194    }
195
196    *certOut = NULL;
197    *chainOut = NULL;
198    *caPubs = NULL;
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    sk_X509_pop_free(*chainOut, X509_free);
256    *chainOut = NULL;
257    sk_X509_pop_free(*caPubs, X509_free);
258    *caPubs = NULL;
259    return NULL;
260}
261
262static 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->certOut == NULL || ctx->sendError == 1
274            || ctx->sendError == OSSL_CMP_MSG_get_bodytype(rr)) {
275        ERR_raise(ERR_LIB_CMP, CMP_R_ERROR_PROCESSING_MESSAGE);
276        return NULL;
277    }
278
279    /* Allow any RR derived from CSR, which may include subject and serial */
280    if (issuer == NULL || serial == NULL)
281        return OSSL_CMP_PKISI_dup(ctx->statusOut);
282
283    /* accept revocation only for the certificate we sent in ir/cr/kur */
284    if (X509_NAME_cmp(issuer, X509_get_issuer_name(ctx->certOut)) != 0
285            || ASN1_INTEGER_cmp(serial,
286                                X509_get0_serialNumber(ctx->certOut)) != 0) {
287        ERR_raise_data(ERR_LIB_CMP, CMP_R_REQUEST_NOT_ACCEPTED,
288                       "wrong certificate to revoke");
289        return NULL;
290    }
291    return OSSL_CMP_PKISI_dup(ctx->statusOut);
292}
293
294static int process_genm(OSSL_CMP_SRV_CTX *srv_ctx,
295                        const OSSL_CMP_MSG *genm,
296                        const STACK_OF(OSSL_CMP_ITAV) *in,
297                        STACK_OF(OSSL_CMP_ITAV) **out)
298{
299    mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx);
300
301    if (ctx == NULL || genm == NULL || in == NULL || out == NULL) {
302        ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT);
303        return 0;
304    }
305    if (ctx->sendError == 1
306            || ctx->sendError == OSSL_CMP_MSG_get_bodytype(genm)
307            || sk_OSSL_CMP_ITAV_num(in) > 1) {
308        ERR_raise(ERR_LIB_CMP, CMP_R_ERROR_PROCESSING_MESSAGE);
309        return 0;
310    }
311
312    *out = sk_OSSL_CMP_ITAV_deep_copy(in, OSSL_CMP_ITAV_dup,
313                                      OSSL_CMP_ITAV_free);
314    return *out != NULL;
315}
316
317static void process_error(OSSL_CMP_SRV_CTX *srv_ctx, const OSSL_CMP_MSG *error,
318                          const OSSL_CMP_PKISI *statusInfo,
319                          const ASN1_INTEGER *errorCode,
320                          const OSSL_CMP_PKIFREETEXT *errorDetails)
321{
322    mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx);
323    char buf[OSSL_CMP_PKISI_BUFLEN];
324    char *sibuf;
325    int i;
326
327    if (ctx == NULL || error == NULL) {
328        ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT);
329        return;
330    }
331
332    BIO_printf(bio_err, "mock server received error:\n");
333
334    if (statusInfo == NULL) {
335        BIO_printf(bio_err, "pkiStatusInfo absent\n");
336    } else {
337        sibuf = OSSL_CMP_snprint_PKIStatusInfo(statusInfo, buf, sizeof(buf));
338        BIO_printf(bio_err, "pkiStatusInfo: %s\n",
339                   sibuf != NULL ? sibuf: "<invalid>");
340    }
341
342    if (errorCode == NULL)
343        BIO_printf(bio_err, "errorCode absent\n");
344    else
345        BIO_printf(bio_err, "errorCode: %ld\n", ASN1_INTEGER_get(errorCode));
346
347    if (sk_ASN1_UTF8STRING_num(errorDetails) <= 0) {
348        BIO_printf(bio_err, "errorDetails absent\n");
349    } else {
350        BIO_printf(bio_err, "errorDetails: ");
351        for (i = 0; i < sk_ASN1_UTF8STRING_num(errorDetails); i++) {
352            if (i > 0)
353                BIO_printf(bio_err, ", ");
354            BIO_printf(bio_err, "\"");
355            ASN1_STRING_print(bio_err,
356                              sk_ASN1_UTF8STRING_value(errorDetails, i));
357            BIO_printf(bio_err, "\"");
358        }
359        BIO_printf(bio_err, "\n");
360    }
361}
362
363static int process_certConf(OSSL_CMP_SRV_CTX *srv_ctx,
364                            const OSSL_CMP_MSG *certConf,
365                            ossl_unused int certReqId,
366                            const ASN1_OCTET_STRING *certHash,
367                            const OSSL_CMP_PKISI *si)
368{
369    mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx);
370    ASN1_OCTET_STRING *digest;
371
372    if (ctx == NULL || certConf == NULL || certHash == NULL) {
373        ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT);
374        return 0;
375    }
376    if (ctx->sendError == 1
377            || ctx->sendError == OSSL_CMP_MSG_get_bodytype(certConf)
378            || ctx->certOut == NULL) {
379        ERR_raise(ERR_LIB_CMP, CMP_R_ERROR_PROCESSING_MESSAGE);
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
394static int process_pollReq(OSSL_CMP_SRV_CTX *srv_ctx,
395                           const OSSL_CMP_MSG *pollReq,
396                           ossl_unused int certReqId,
397                           OSSL_CMP_MSG **certReq, int64_t *check_after)
398{
399    mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx);
400
401    if (ctx == NULL || pollReq == NULL
402            || certReq == NULL || check_after == NULL) {
403        ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT);
404        return 0;
405    }
406    if (ctx->sendError == 1
407            || ctx->sendError == OSSL_CMP_MSG_get_bodytype(pollReq)) {
408        *certReq = NULL;
409        ERR_raise(ERR_LIB_CMP, CMP_R_ERROR_PROCESSING_MESSAGE);
410        return 0;
411    }
412    if (ctx->certReq == NULL) {
413        /* not currently in polling mode */
414        *certReq = NULL;
415        ERR_raise(ERR_LIB_CMP, CMP_R_UNEXPECTED_PKIBODY);
416        return 0;
417    }
418
419    if (++ctx->curr_pollCount >= ctx->pollCount) {
420        /* end polling */
421        *certReq = ctx->certReq;
422        ctx->certReq = NULL;
423        *check_after = 0;
424    } else {
425        *certReq = NULL;
426        *check_after = ctx->checkAfterTime;
427    }
428    return 1;
429}
430
431OSSL_CMP_SRV_CTX *ossl_cmp_mock_srv_new(OSSL_LIB_CTX *libctx, const char *propq)
432{
433    OSSL_CMP_SRV_CTX *srv_ctx = OSSL_CMP_SRV_CTX_new(libctx, propq);
434    mock_srv_ctx *ctx = mock_srv_ctx_new();
435
436    if (srv_ctx != NULL && ctx != NULL
437            && OSSL_CMP_SRV_CTX_init(srv_ctx, ctx, process_cert_request,
438                                     process_rr, process_genm, process_error,
439                                     process_certConf, process_pollReq))
440        return srv_ctx;
441
442    mock_srv_ctx_free(ctx);
443    OSSL_CMP_SRV_CTX_free(srv_ctx);
444    return NULL;
445}
446
447void ossl_cmp_mock_srv_free(OSSL_CMP_SRV_CTX *srv_ctx)
448{
449    if (srv_ctx != NULL)
450        mock_srv_ctx_free(OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx));
451    OSSL_CMP_SRV_CTX_free(srv_ctx);
452}
453