1/*
2 * Copyright 1999-2021 The OpenSSL Project Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License 2.0 (the "License").  You may not use
5 * this file except in compliance with the License.  You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
8 */
9
10#include <stdio.h>
11#include "internal/cryptlib.h"
12#include <openssl/conf.h>
13#include <openssl/asn1.h>
14#include <openssl/asn1t.h>
15#include <openssl/x509v3.h>
16
17#include "x509_local.h"
18#include "pcy_local.h"
19#include "ext_dat.h"
20
21/* Certificate policies extension support: this one is a bit complex... */
22
23static int i2r_certpol(X509V3_EXT_METHOD *method, STACK_OF(POLICYINFO) *pol,
24                       BIO *out, int indent);
25static STACK_OF(POLICYINFO) *r2i_certpol(X509V3_EXT_METHOD *method,
26                                         X509V3_CTX *ctx, const char *value);
27static void print_qualifiers(BIO *out, STACK_OF(POLICYQUALINFO) *quals,
28                             int indent);
29static void print_notice(BIO *out, USERNOTICE *notice, int indent);
30static POLICYINFO *policy_section(X509V3_CTX *ctx,
31                                  STACK_OF(CONF_VALUE) *polstrs, int ia5org);
32static POLICYQUALINFO *notice_section(X509V3_CTX *ctx,
33                                      STACK_OF(CONF_VALUE) *unot, int ia5org);
34static int nref_nos(STACK_OF(ASN1_INTEGER) *nnums, STACK_OF(CONF_VALUE) *nos);
35static int displaytext_str2tag(const char *tagstr, unsigned int *tag_len);
36static int displaytext_get_tag_len(const char *tagstr);
37
38const X509V3_EXT_METHOD ossl_v3_cpols = {
39    NID_certificate_policies, 0, ASN1_ITEM_ref(CERTIFICATEPOLICIES),
40    0, 0, 0, 0,
41    0, 0,
42    0, 0,
43    (X509V3_EXT_I2R)i2r_certpol,
44    (X509V3_EXT_R2I)r2i_certpol,
45    NULL
46};
47
48ASN1_ITEM_TEMPLATE(CERTIFICATEPOLICIES) =
49        ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, CERTIFICATEPOLICIES, POLICYINFO)
50ASN1_ITEM_TEMPLATE_END(CERTIFICATEPOLICIES)
51
52IMPLEMENT_ASN1_FUNCTIONS(CERTIFICATEPOLICIES)
53
54ASN1_SEQUENCE(POLICYINFO) = {
55        ASN1_SIMPLE(POLICYINFO, policyid, ASN1_OBJECT),
56        ASN1_SEQUENCE_OF_OPT(POLICYINFO, qualifiers, POLICYQUALINFO)
57} ASN1_SEQUENCE_END(POLICYINFO)
58
59IMPLEMENT_ASN1_FUNCTIONS(POLICYINFO)
60
61ASN1_ADB_TEMPLATE(policydefault) = ASN1_SIMPLE(POLICYQUALINFO, d.other, ASN1_ANY);
62
63ASN1_ADB(POLICYQUALINFO) = {
64        ADB_ENTRY(NID_id_qt_cps, ASN1_SIMPLE(POLICYQUALINFO, d.cpsuri, ASN1_IA5STRING)),
65        ADB_ENTRY(NID_id_qt_unotice, ASN1_SIMPLE(POLICYQUALINFO, d.usernotice, USERNOTICE))
66} ASN1_ADB_END(POLICYQUALINFO, 0, pqualid, 0, &policydefault_tt, NULL);
67
68ASN1_SEQUENCE(POLICYQUALINFO) = {
69        ASN1_SIMPLE(POLICYQUALINFO, pqualid, ASN1_OBJECT),
70        ASN1_ADB_OBJECT(POLICYQUALINFO)
71} ASN1_SEQUENCE_END(POLICYQUALINFO)
72
73IMPLEMENT_ASN1_FUNCTIONS(POLICYQUALINFO)
74
75ASN1_SEQUENCE(USERNOTICE) = {
76        ASN1_OPT(USERNOTICE, noticeref, NOTICEREF),
77        ASN1_OPT(USERNOTICE, exptext, DISPLAYTEXT)
78} ASN1_SEQUENCE_END(USERNOTICE)
79
80IMPLEMENT_ASN1_FUNCTIONS(USERNOTICE)
81
82ASN1_SEQUENCE(NOTICEREF) = {
83        ASN1_SIMPLE(NOTICEREF, organization, DISPLAYTEXT),
84        ASN1_SEQUENCE_OF(NOTICEREF, noticenos, ASN1_INTEGER)
85} ASN1_SEQUENCE_END(NOTICEREF)
86
87IMPLEMENT_ASN1_FUNCTIONS(NOTICEREF)
88
89static STACK_OF(POLICYINFO) *r2i_certpol(X509V3_EXT_METHOD *method,
90                                         X509V3_CTX *ctx, const char *value)
91{
92    STACK_OF(POLICYINFO) *pols;
93    char *pstr;
94    POLICYINFO *pol;
95    ASN1_OBJECT *pobj;
96    STACK_OF(CONF_VALUE) *vals = X509V3_parse_list(value);
97    CONF_VALUE *cnf;
98    const int num = sk_CONF_VALUE_num(vals);
99    int i, ia5org;
100
101    if (vals == NULL) {
102        ERR_raise(ERR_LIB_X509V3, ERR_R_X509V3_LIB);
103        return NULL;
104    }
105
106    pols = sk_POLICYINFO_new_reserve(NULL, num);
107    if (pols == NULL) {
108        ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
109        goto err;
110    }
111
112    ia5org = 0;
113    for (i = 0; i < num; i++) {
114        cnf = sk_CONF_VALUE_value(vals, i);
115        if (cnf->value != NULL || cnf->name == NULL) {
116            ERR_raise(ERR_LIB_X509V3, X509V3_R_INVALID_POLICY_IDENTIFIER);
117            X509V3_conf_add_error_name_value(cnf);
118            goto err;
119        }
120        pstr = cnf->name;
121        if (strcmp(pstr, "ia5org") == 0) {
122            ia5org = 1;
123            continue;
124        } else if (*pstr == '@') {
125            STACK_OF(CONF_VALUE) *polsect;
126
127            polsect = X509V3_get_section(ctx, pstr + 1);
128            if (polsect == NULL) {
129                ERR_raise_data(ERR_LIB_X509V3, X509V3_R_INVALID_SECTION,
130                               "%s", cnf->name);
131                goto err;
132            }
133            pol = policy_section(ctx, polsect, ia5org);
134            X509V3_section_free(ctx, polsect);
135            if (pol == NULL)
136                goto err;
137        } else {
138            if ((pobj = OBJ_txt2obj(cnf->name, 0)) == NULL) {
139                ERR_raise_data(ERR_LIB_X509V3,
140                               X509V3_R_INVALID_OBJECT_IDENTIFIER,
141                               "%s", cnf->name);
142                goto err;
143            }
144            pol = POLICYINFO_new();
145            if (pol == NULL) {
146                ASN1_OBJECT_free(pobj);
147                ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
148                goto err;
149            }
150            pol->policyid = pobj;
151        }
152        if (!sk_POLICYINFO_push(pols, pol)) {
153            POLICYINFO_free(pol);
154            ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
155            goto err;
156        }
157    }
158    sk_CONF_VALUE_pop_free(vals, X509V3_conf_free);
159    return pols;
160 err:
161    sk_CONF_VALUE_pop_free(vals, X509V3_conf_free);
162    sk_POLICYINFO_pop_free(pols, POLICYINFO_free);
163    return NULL;
164}
165
166static POLICYINFO *policy_section(X509V3_CTX *ctx,
167                                  STACK_OF(CONF_VALUE) *polstrs, int ia5org)
168{
169    int i;
170    CONF_VALUE *cnf;
171    POLICYINFO *pol;
172    POLICYQUALINFO *qual;
173
174    if ((pol = POLICYINFO_new()) == NULL)
175        goto merr;
176    for (i = 0; i < sk_CONF_VALUE_num(polstrs); i++) {
177        cnf = sk_CONF_VALUE_value(polstrs, i);
178        if (strcmp(cnf->name, "policyIdentifier") == 0) {
179            ASN1_OBJECT *pobj;
180
181            if ((pobj = OBJ_txt2obj(cnf->value, 0)) == NULL) {
182                ERR_raise(ERR_LIB_X509V3, X509V3_R_INVALID_OBJECT_IDENTIFIER);
183                X509V3_conf_err(cnf);
184                goto err;
185            }
186            pol->policyid = pobj;
187
188        } else if (!ossl_v3_name_cmp(cnf->name, "CPS")) {
189            if (pol->qualifiers == NULL)
190                pol->qualifiers = sk_POLICYQUALINFO_new_null();
191            if ((qual = POLICYQUALINFO_new()) == NULL)
192                goto merr;
193            if (!sk_POLICYQUALINFO_push(pol->qualifiers, qual))
194                goto merr;
195            if ((qual->pqualid = OBJ_nid2obj(NID_id_qt_cps)) == NULL) {
196                ERR_raise(ERR_LIB_X509V3, ERR_R_INTERNAL_ERROR);
197                goto err;
198            }
199            if ((qual->d.cpsuri = ASN1_IA5STRING_new()) == NULL)
200                goto merr;
201            if (!ASN1_STRING_set(qual->d.cpsuri, cnf->value,
202                                 strlen(cnf->value)))
203                goto merr;
204        } else if (!ossl_v3_name_cmp(cnf->name, "userNotice")) {
205            STACK_OF(CONF_VALUE) *unot;
206            if (*cnf->value != '@') {
207                ERR_raise(ERR_LIB_X509V3, X509V3_R_EXPECTED_A_SECTION_NAME);
208                X509V3_conf_err(cnf);
209                goto err;
210            }
211            unot = X509V3_get_section(ctx, cnf->value + 1);
212            if (!unot) {
213                ERR_raise(ERR_LIB_X509V3, X509V3_R_INVALID_SECTION);
214
215                X509V3_conf_err(cnf);
216                goto err;
217            }
218            qual = notice_section(ctx, unot, ia5org);
219            X509V3_section_free(ctx, unot);
220            if (!qual)
221                goto err;
222            if (pol->qualifiers == NULL)
223                pol->qualifiers = sk_POLICYQUALINFO_new_null();
224            if (!sk_POLICYQUALINFO_push(pol->qualifiers, qual))
225                goto merr;
226        } else {
227            ERR_raise(ERR_LIB_X509V3, X509V3_R_INVALID_OPTION);
228            X509V3_conf_err(cnf);
229            goto err;
230        }
231    }
232    if (pol->policyid == NULL) {
233        ERR_raise(ERR_LIB_X509V3, X509V3_R_NO_POLICY_IDENTIFIER);
234        goto err;
235    }
236
237    return pol;
238
239 merr:
240    ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
241
242 err:
243    POLICYINFO_free(pol);
244    return NULL;
245}
246
247static int displaytext_get_tag_len(const char *tagstr)
248{
249    char *colon = strchr(tagstr, ':');
250
251    return (colon == NULL) ? -1 : colon - tagstr;
252}
253
254static int displaytext_str2tag(const char *tagstr, unsigned int *tag_len)
255{
256    int len;
257
258    *tag_len = 0;
259    len = displaytext_get_tag_len(tagstr);
260
261    if (len == -1)
262        return V_ASN1_VISIBLESTRING;
263    *tag_len = len;
264    if (len == sizeof("UTF8") - 1 && strncmp(tagstr, "UTF8", len) == 0)
265        return V_ASN1_UTF8STRING;
266    if (len == sizeof("UTF8String") - 1 && strncmp(tagstr, "UTF8String", len) == 0)
267        return V_ASN1_UTF8STRING;
268    if (len == sizeof("BMP") - 1 && strncmp(tagstr, "BMP", len) == 0)
269        return V_ASN1_BMPSTRING;
270    if (len == sizeof("BMPSTRING") - 1 && strncmp(tagstr, "BMPSTRING", len) == 0)
271        return V_ASN1_BMPSTRING;
272    if (len == sizeof("VISIBLE") - 1 && strncmp(tagstr, "VISIBLE", len) == 0)
273        return V_ASN1_VISIBLESTRING;
274    if (len == sizeof("VISIBLESTRING") - 1 && strncmp(tagstr, "VISIBLESTRING", len) == 0)
275        return V_ASN1_VISIBLESTRING;
276    *tag_len = 0;
277    return V_ASN1_VISIBLESTRING;
278}
279
280static POLICYQUALINFO *notice_section(X509V3_CTX *ctx,
281                                      STACK_OF(CONF_VALUE) *unot, int ia5org)
282{
283    int i, ret, len, tag;
284    unsigned int tag_len;
285    CONF_VALUE *cnf;
286    USERNOTICE *not;
287    POLICYQUALINFO *qual;
288    char *value = NULL;
289
290    if ((qual = POLICYQUALINFO_new()) == NULL)
291        goto merr;
292    if ((qual->pqualid = OBJ_nid2obj(NID_id_qt_unotice)) == NULL) {
293        ERR_raise(ERR_LIB_X509V3, ERR_R_INTERNAL_ERROR);
294        goto err;
295    }
296    if ((not = USERNOTICE_new()) == NULL)
297        goto merr;
298    qual->d.usernotice = not;
299    for (i = 0; i < sk_CONF_VALUE_num(unot); i++) {
300        cnf = sk_CONF_VALUE_value(unot, i);
301
302        value = cnf->value;
303        if (strcmp(cnf->name, "explicitText") == 0) {
304            tag = displaytext_str2tag(value, &tag_len);
305            if ((not->exptext = ASN1_STRING_type_new(tag)) == NULL)
306                goto merr;
307            if (tag_len != 0)
308                value += tag_len + 1;
309            len = strlen(value);
310            if (!ASN1_STRING_set(not->exptext, value, len))
311                goto merr;
312        } else if (strcmp(cnf->name, "organization") == 0) {
313            NOTICEREF *nref;
314
315            if (!not->noticeref) {
316                if ((nref = NOTICEREF_new()) == NULL)
317                    goto merr;
318                not->noticeref = nref;
319            } else
320                nref = not->noticeref;
321            if (ia5org)
322                nref->organization->type = V_ASN1_IA5STRING;
323            else
324                nref->organization->type = V_ASN1_VISIBLESTRING;
325            if (!ASN1_STRING_set(nref->organization, cnf->value,
326                                 strlen(cnf->value)))
327                goto merr;
328        } else if (strcmp(cnf->name, "noticeNumbers") == 0) {
329            NOTICEREF *nref;
330
331            STACK_OF(CONF_VALUE) *nos;
332            if (!not->noticeref) {
333                if ((nref = NOTICEREF_new()) == NULL)
334                    goto merr;
335                not->noticeref = nref;
336            } else
337                nref = not->noticeref;
338            nos = X509V3_parse_list(cnf->value);
339            if (!nos || !sk_CONF_VALUE_num(nos)) {
340                ERR_raise(ERR_LIB_X509V3, X509V3_R_INVALID_NUMBERS);
341                X509V3_conf_add_error_name_value(cnf);
342                sk_CONF_VALUE_pop_free(nos, X509V3_conf_free);
343                goto err;
344            }
345            ret = nref_nos(nref->noticenos, nos);
346            sk_CONF_VALUE_pop_free(nos, X509V3_conf_free);
347            if (!ret)
348                goto err;
349        } else {
350            ERR_raise(ERR_LIB_X509V3, X509V3_R_INVALID_OPTION);
351            X509V3_conf_add_error_name_value(cnf);
352            goto err;
353        }
354    }
355
356    if (not->noticeref &&
357        (!not->noticeref->noticenos || !not->noticeref->organization)) {
358        ERR_raise(ERR_LIB_X509V3, X509V3_R_NEED_ORGANIZATION_AND_NUMBERS);
359        goto err;
360    }
361
362    return qual;
363
364 merr:
365    ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
366
367 err:
368    POLICYQUALINFO_free(qual);
369    return NULL;
370}
371
372static int nref_nos(STACK_OF(ASN1_INTEGER) *nnums, STACK_OF(CONF_VALUE) *nos)
373{
374    CONF_VALUE *cnf;
375    ASN1_INTEGER *aint;
376
377    int i;
378
379    for (i = 0; i < sk_CONF_VALUE_num(nos); i++) {
380        cnf = sk_CONF_VALUE_value(nos, i);
381        if ((aint = s2i_ASN1_INTEGER(NULL, cnf->name)) == NULL) {
382            ERR_raise(ERR_LIB_X509V3, X509V3_R_INVALID_NUMBER);
383            goto err;
384        }
385        if (!sk_ASN1_INTEGER_push(nnums, aint))
386            goto merr;
387    }
388    return 1;
389
390 merr:
391    ASN1_INTEGER_free(aint);
392    ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
393
394 err:
395    return 0;
396}
397
398static int i2r_certpol(X509V3_EXT_METHOD *method, STACK_OF(POLICYINFO) *pol,
399                       BIO *out, int indent)
400{
401    int i;
402    POLICYINFO *pinfo;
403    /* First print out the policy OIDs */
404    for (i = 0; i < sk_POLICYINFO_num(pol); i++) {
405        if (i > 0)
406            BIO_puts(out, "\n");
407        pinfo = sk_POLICYINFO_value(pol, i);
408        BIO_printf(out, "%*sPolicy: ", indent, "");
409        i2a_ASN1_OBJECT(out, pinfo->policyid);
410        if (pinfo->qualifiers) {
411            BIO_puts(out, "\n");
412            print_qualifiers(out, pinfo->qualifiers, indent + 2);
413        }
414    }
415    return 1;
416}
417
418static void print_qualifiers(BIO *out, STACK_OF(POLICYQUALINFO) *quals,
419                             int indent)
420{
421    POLICYQUALINFO *qualinfo;
422    int i;
423    for (i = 0; i < sk_POLICYQUALINFO_num(quals); i++) {
424        if (i > 0)
425            BIO_puts(out, "\n");
426        qualinfo = sk_POLICYQUALINFO_value(quals, i);
427        switch (OBJ_obj2nid(qualinfo->pqualid)) {
428        case NID_id_qt_cps:
429            BIO_printf(out, "%*sCPS: %.*s", indent, "",
430                       qualinfo->d.cpsuri->length,
431                       qualinfo->d.cpsuri->data);
432            break;
433
434        case NID_id_qt_unotice:
435            BIO_printf(out, "%*sUser Notice:\n", indent, "");
436            print_notice(out, qualinfo->d.usernotice, indent + 2);
437            break;
438
439        default:
440            BIO_printf(out, "%*sUnknown Qualifier: ", indent + 2, "");
441
442            i2a_ASN1_OBJECT(out, qualinfo->pqualid);
443            break;
444        }
445    }
446}
447
448static void print_notice(BIO *out, USERNOTICE *notice, int indent)
449{
450    int i;
451    if (notice->noticeref) {
452        NOTICEREF *ref;
453        ref = notice->noticeref;
454        BIO_printf(out, "%*sOrganization: %.*s\n", indent, "",
455                   ref->organization->length,
456                   ref->organization->data);
457        BIO_printf(out, "%*sNumber%s: ", indent, "",
458                   sk_ASN1_INTEGER_num(ref->noticenos) > 1 ? "s" : "");
459        for (i = 0; i < sk_ASN1_INTEGER_num(ref->noticenos); i++) {
460            ASN1_INTEGER *num;
461            char *tmp;
462            num = sk_ASN1_INTEGER_value(ref->noticenos, i);
463            if (i)
464                BIO_puts(out, ", ");
465            if (num == NULL)
466                BIO_puts(out, "(null)");
467            else {
468                tmp = i2s_ASN1_INTEGER(NULL, num);
469                if (tmp == NULL)
470                    return;
471                BIO_puts(out, tmp);
472                OPENSSL_free(tmp);
473            }
474        }
475        if (notice->exptext)
476            BIO_puts(out, "\n");
477    }
478    if (notice->exptext)
479        BIO_printf(out, "%*sExplicit Text: %.*s", indent, "",
480                   notice->exptext->length,
481                   notice->exptext->data);
482}
483
484void X509_POLICY_NODE_print(BIO *out, X509_POLICY_NODE *node, int indent)
485{
486    const X509_POLICY_DATA *dat = node->data;
487
488    BIO_printf(out, "%*sPolicy: ", indent, "");
489
490    i2a_ASN1_OBJECT(out, dat->valid_policy);
491    BIO_puts(out, "\n");
492    BIO_printf(out, "%*s%s\n", indent + 2, "",
493               node_data_critical(dat) ? "Critical" : "Non Critical");
494    if (dat->qualifier_set) {
495        print_qualifiers(out, dat->qualifier_set, indent + 2);
496        BIO_puts(out, "\n");
497    }
498    else
499        BIO_printf(out, "%*sNo Qualifiers\n", indent + 2, "");
500}
501