2 * Copyright 1999-2018 The OpenSSL Project Authors. All Rights Reserved.
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
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>
17 #include "pcy_local.h"
20 /* Certificate policies extension support: this one is a bit complex... */
22 static int i2r_certpol(X509V3_EXT_METHOD
*method
, STACK_OF(POLICYINFO
) *pol
,
23 BIO
*out
, int indent
);
24 static STACK_OF(POLICYINFO
) *r2i_certpol(X509V3_EXT_METHOD
*method
,
25 X509V3_CTX
*ctx
, const char *value
);
26 static void print_qualifiers(BIO
*out
, STACK_OF(POLICYQUALINFO
) *quals
,
28 static void print_notice(BIO
*out
, USERNOTICE
*notice
, int indent
);
29 static POLICYINFO
*policy_section(X509V3_CTX
*ctx
,
30 STACK_OF(CONF_VALUE
) *polstrs
, int ia5org
);
31 static POLICYQUALINFO
*notice_section(X509V3_CTX
*ctx
,
32 STACK_OF(CONF_VALUE
) *unot
, int ia5org
);
33 static int nref_nos(STACK_OF(ASN1_INTEGER
) *nnums
, STACK_OF(CONF_VALUE
) *nos
);
34 static int displaytext_str2tag(const char *tagstr
, unsigned int *tag_len
);
35 static int displaytext_get_tag_len(const char *tagstr
);
37 const X509V3_EXT_METHOD v3_cpols
= {
38 NID_certificate_policies
, 0, ASN1_ITEM_ref(CERTIFICATEPOLICIES
),
42 (X509V3_EXT_I2R
)i2r_certpol
,
43 (X509V3_EXT_R2I
)r2i_certpol
,
47 ASN1_ITEM_TEMPLATE(CERTIFICATEPOLICIES
) =
48 ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF
, 0, CERTIFICATEPOLICIES
, POLICYINFO
)
49 ASN1_ITEM_TEMPLATE_END(CERTIFICATEPOLICIES
)
51 IMPLEMENT_ASN1_FUNCTIONS(CERTIFICATEPOLICIES
)
53 ASN1_SEQUENCE(POLICYINFO
) = {
54 ASN1_SIMPLE(POLICYINFO
, policyid
, ASN1_OBJECT
),
55 ASN1_SEQUENCE_OF_OPT(POLICYINFO
, qualifiers
, POLICYQUALINFO
)
56 } ASN1_SEQUENCE_END(POLICYINFO
)
58 IMPLEMENT_ASN1_FUNCTIONS(POLICYINFO
)
60 ASN1_ADB_TEMPLATE(policydefault
) = ASN1_SIMPLE(POLICYQUALINFO
, d
.other
, ASN1_ANY
);
62 ASN1_ADB(POLICYQUALINFO
) = {
63 ADB_ENTRY(NID_id_qt_cps
, ASN1_SIMPLE(POLICYQUALINFO
, d
.cpsuri
, ASN1_IA5STRING
)),
64 ADB_ENTRY(NID_id_qt_unotice
, ASN1_SIMPLE(POLICYQUALINFO
, d
.usernotice
, USERNOTICE
))
65 } ASN1_ADB_END(POLICYQUALINFO
, 0, pqualid
, 0, &policydefault_tt
, NULL
);
67 ASN1_SEQUENCE(POLICYQUALINFO
) = {
68 ASN1_SIMPLE(POLICYQUALINFO
, pqualid
, ASN1_OBJECT
),
69 ASN1_ADB_OBJECT(POLICYQUALINFO
)
70 } ASN1_SEQUENCE_END(POLICYQUALINFO
)
72 IMPLEMENT_ASN1_FUNCTIONS(POLICYQUALINFO
)
74 ASN1_SEQUENCE(USERNOTICE
) = {
75 ASN1_OPT(USERNOTICE
, noticeref
, NOTICEREF
),
76 ASN1_OPT(USERNOTICE
, exptext
, DISPLAYTEXT
)
77 } ASN1_SEQUENCE_END(USERNOTICE
)
79 IMPLEMENT_ASN1_FUNCTIONS(USERNOTICE
)
81 ASN1_SEQUENCE(NOTICEREF
) = {
82 ASN1_SIMPLE(NOTICEREF
, organization
, DISPLAYTEXT
),
83 ASN1_SEQUENCE_OF(NOTICEREF
, noticenos
, ASN1_INTEGER
)
84 } ASN1_SEQUENCE_END(NOTICEREF
)
86 IMPLEMENT_ASN1_FUNCTIONS(NOTICEREF
)
88 static STACK_OF(POLICYINFO
) *r2i_certpol(X509V3_EXT_METHOD
*method
,
89 X509V3_CTX
*ctx
, const char *value
)
91 STACK_OF(POLICYINFO
) *pols
;
95 STACK_OF(CONF_VALUE
) *vals
= X509V3_parse_list(value
);
97 const int num
= sk_CONF_VALUE_num(vals
);
101 X509V3err(X509V3_F_R2I_CERTPOL
, ERR_R_X509V3_LIB
);
105 pols
= sk_POLICYINFO_new_reserve(NULL
, num
);
107 X509V3err(X509V3_F_R2I_CERTPOL
, ERR_R_MALLOC_FAILURE
);
112 for (i
= 0; i
< num
; i
++) {
113 cnf
= sk_CONF_VALUE_value(vals
, i
);
115 if (cnf
->value
|| !cnf
->name
) {
116 X509V3err(X509V3_F_R2I_CERTPOL
,
117 X509V3_R_INVALID_POLICY_IDENTIFIER
);
118 X509V3_conf_err(cnf
);
122 if (strcmp(pstr
, "ia5org") == 0) {
125 } else if (*pstr
== '@') {
126 STACK_OF(CONF_VALUE
) *polsect
;
128 polsect
= X509V3_get_section(ctx
, pstr
+ 1);
129 if (polsect
== NULL
) {
130 X509V3err(X509V3_F_R2I_CERTPOL
, X509V3_R_INVALID_SECTION
);
132 X509V3_conf_err(cnf
);
135 pol
= policy_section(ctx
, polsect
, ia5org
);
136 X509V3_section_free(ctx
, polsect
);
140 if ((pobj
= OBJ_txt2obj(cnf
->name
, 0)) == NULL
) {
141 X509V3err(X509V3_F_R2I_CERTPOL
,
142 X509V3_R_INVALID_OBJECT_IDENTIFIER
);
143 X509V3_conf_err(cnf
);
146 pol
= POLICYINFO_new();
148 ASN1_OBJECT_free(pobj
);
149 X509V3err(X509V3_F_R2I_CERTPOL
, ERR_R_MALLOC_FAILURE
);
152 pol
->policyid
= pobj
;
154 if (!sk_POLICYINFO_push(pols
, pol
)) {
155 POLICYINFO_free(pol
);
156 X509V3err(X509V3_F_R2I_CERTPOL
, ERR_R_MALLOC_FAILURE
);
160 sk_CONF_VALUE_pop_free(vals
, X509V3_conf_free
);
163 sk_CONF_VALUE_pop_free(vals
, X509V3_conf_free
);
164 sk_POLICYINFO_pop_free(pols
, POLICYINFO_free
);
168 static POLICYINFO
*policy_section(X509V3_CTX
*ctx
,
169 STACK_OF(CONF_VALUE
) *polstrs
, int ia5org
)
174 POLICYQUALINFO
*qual
;
176 if ((pol
= POLICYINFO_new()) == NULL
)
178 for (i
= 0; i
< sk_CONF_VALUE_num(polstrs
); i
++) {
179 cnf
= sk_CONF_VALUE_value(polstrs
, i
);
180 if (strcmp(cnf
->name
, "policyIdentifier") == 0) {
182 if ((pobj
= OBJ_txt2obj(cnf
->value
, 0)) == NULL
) {
183 X509V3err(X509V3_F_POLICY_SECTION
,
184 X509V3_R_INVALID_OBJECT_IDENTIFIER
);
185 X509V3_conf_err(cnf
);
188 pol
->policyid
= pobj
;
190 } else if (!v3_name_cmp(cnf
->name
, "CPS")) {
191 if (pol
->qualifiers
== NULL
)
192 pol
->qualifiers
= sk_POLICYQUALINFO_new_null();
193 if ((qual
= POLICYQUALINFO_new()) == NULL
)
195 if (!sk_POLICYQUALINFO_push(pol
->qualifiers
, qual
))
197 if ((qual
->pqualid
= OBJ_nid2obj(NID_id_qt_cps
)) == NULL
) {
198 X509V3err(X509V3_F_POLICY_SECTION
, ERR_R_INTERNAL_ERROR
);
201 if ((qual
->d
.cpsuri
= ASN1_IA5STRING_new()) == NULL
)
203 if (!ASN1_STRING_set(qual
->d
.cpsuri
, cnf
->value
,
206 } else if (!v3_name_cmp(cnf
->name
, "userNotice")) {
207 STACK_OF(CONF_VALUE
) *unot
;
208 if (*cnf
->value
!= '@') {
209 X509V3err(X509V3_F_POLICY_SECTION
,
210 X509V3_R_EXPECTED_A_SECTION_NAME
);
211 X509V3_conf_err(cnf
);
214 unot
= X509V3_get_section(ctx
, cnf
->value
+ 1);
216 X509V3err(X509V3_F_POLICY_SECTION
, X509V3_R_INVALID_SECTION
);
218 X509V3_conf_err(cnf
);
221 qual
= notice_section(ctx
, unot
, ia5org
);
222 X509V3_section_free(ctx
, unot
);
225 if (pol
->qualifiers
== NULL
)
226 pol
->qualifiers
= sk_POLICYQUALINFO_new_null();
227 if (!sk_POLICYQUALINFO_push(pol
->qualifiers
, qual
))
230 X509V3err(X509V3_F_POLICY_SECTION
, X509V3_R_INVALID_OPTION
);
232 X509V3_conf_err(cnf
);
236 if (pol
->policyid
== NULL
) {
237 X509V3err(X509V3_F_POLICY_SECTION
, X509V3_R_NO_POLICY_IDENTIFIER
);
244 X509V3err(X509V3_F_POLICY_SECTION
, ERR_R_MALLOC_FAILURE
);
247 POLICYINFO_free(pol
);
251 static int displaytext_get_tag_len(const char *tagstr
)
253 char *colon
= strchr(tagstr
, ':');
255 return (colon
== NULL
) ? -1 : colon
- tagstr
;
258 static int displaytext_str2tag(const char *tagstr
, unsigned int *tag_len
)
263 len
= displaytext_get_tag_len(tagstr
);
266 return V_ASN1_VISIBLESTRING
;
268 if (len
== sizeof("UTF8") - 1 && strncmp(tagstr
, "UTF8", len
) == 0)
269 return V_ASN1_UTF8STRING
;
270 if (len
== sizeof("UTF8String") - 1 && strncmp(tagstr
, "UTF8String", len
) == 0)
271 return V_ASN1_UTF8STRING
;
272 if (len
== sizeof("BMP") - 1 && strncmp(tagstr
, "BMP", len
) == 0)
273 return V_ASN1_BMPSTRING
;
274 if (len
== sizeof("BMPSTRING") - 1 && strncmp(tagstr
, "BMPSTRING", len
) == 0)
275 return V_ASN1_BMPSTRING
;
276 if (len
== sizeof("VISIBLE") - 1 && strncmp(tagstr
, "VISIBLE", len
) == 0)
277 return V_ASN1_VISIBLESTRING
;
278 if (len
== sizeof("VISIBLESTRING") - 1 && strncmp(tagstr
, "VISIBLESTRING", len
) == 0)
279 return V_ASN1_VISIBLESTRING
;
281 return V_ASN1_VISIBLESTRING
;
284 static POLICYQUALINFO
*notice_section(X509V3_CTX
*ctx
,
285 STACK_OF(CONF_VALUE
) *unot
, int ia5org
)
287 int i
, ret
, len
, tag
;
288 unsigned int tag_len
;
291 POLICYQUALINFO
*qual
;
294 if ((qual
= POLICYQUALINFO_new()) == NULL
)
296 if ((qual
->pqualid
= OBJ_nid2obj(NID_id_qt_unotice
)) == NULL
) {
297 X509V3err(X509V3_F_NOTICE_SECTION
, ERR_R_INTERNAL_ERROR
);
300 if ((not = USERNOTICE_new()) == NULL
)
302 qual
->d
.usernotice
= not;
303 for (i
= 0; i
< sk_CONF_VALUE_num(unot
); i
++) {
304 cnf
= sk_CONF_VALUE_value(unot
, i
);
306 if (strcmp(cnf
->name
, "explicitText") == 0) {
307 tag
= displaytext_str2tag(value
, &tag_len
);
308 if ((not->exptext
= ASN1_STRING_type_new(tag
)) == NULL
)
311 value
+= tag_len
+ 1;
313 if (!ASN1_STRING_set(not->exptext
, value
, len
))
315 } else if (strcmp(cnf
->name
, "organization") == 0) {
317 if (!not->noticeref
) {
318 if ((nref
= NOTICEREF_new()) == NULL
)
320 not->noticeref
= nref
;
322 nref
= not->noticeref
;
324 nref
->organization
->type
= V_ASN1_IA5STRING
;
326 nref
->organization
->type
= V_ASN1_VISIBLESTRING
;
327 if (!ASN1_STRING_set(nref
->organization
, cnf
->value
,
330 } else if (strcmp(cnf
->name
, "noticeNumbers") == 0) {
332 STACK_OF(CONF_VALUE
) *nos
;
333 if (!not->noticeref
) {
334 if ((nref
= NOTICEREF_new()) == NULL
)
336 not->noticeref
= nref
;
338 nref
= not->noticeref
;
339 nos
= X509V3_parse_list(cnf
->value
);
340 if (!nos
|| !sk_CONF_VALUE_num(nos
)) {
341 X509V3err(X509V3_F_NOTICE_SECTION
, X509V3_R_INVALID_NUMBERS
);
342 X509V3_conf_err(cnf
);
343 sk_CONF_VALUE_pop_free(nos
, X509V3_conf_free
);
346 ret
= nref_nos(nref
->noticenos
, nos
);
347 sk_CONF_VALUE_pop_free(nos
, X509V3_conf_free
);
351 X509V3err(X509V3_F_NOTICE_SECTION
, X509V3_R_INVALID_OPTION
);
352 X509V3_conf_err(cnf
);
357 if (not->noticeref
&&
358 (!not->noticeref
->noticenos
|| !not->noticeref
->organization
)) {
359 X509V3err(X509V3_F_NOTICE_SECTION
,
360 X509V3_R_NEED_ORGANIZATION_AND_NUMBERS
);
367 X509V3err(X509V3_F_NOTICE_SECTION
, ERR_R_MALLOC_FAILURE
);
370 POLICYQUALINFO_free(qual
);
374 static int nref_nos(STACK_OF(ASN1_INTEGER
) *nnums
, STACK_OF(CONF_VALUE
) *nos
)
381 for (i
= 0; i
< sk_CONF_VALUE_num(nos
); i
++) {
382 cnf
= sk_CONF_VALUE_value(nos
, i
);
383 if ((aint
= s2i_ASN1_INTEGER(NULL
, cnf
->name
)) == NULL
) {
384 X509V3err(X509V3_F_NREF_NOS
, X509V3_R_INVALID_NUMBER
);
387 if (!sk_ASN1_INTEGER_push(nnums
, aint
))
393 ASN1_INTEGER_free(aint
);
394 X509V3err(X509V3_F_NREF_NOS
, ERR_R_MALLOC_FAILURE
);
400 static int i2r_certpol(X509V3_EXT_METHOD
*method
, STACK_OF(POLICYINFO
) *pol
,
401 BIO
*out
, int indent
)
405 /* First print out the policy OIDs */
406 for (i
= 0; i
< sk_POLICYINFO_num(pol
); i
++) {
409 pinfo
= sk_POLICYINFO_value(pol
, i
);
410 BIO_printf(out
, "%*sPolicy: ", indent
, "");
411 i2a_ASN1_OBJECT(out
, pinfo
->policyid
);
412 if (pinfo
->qualifiers
) {
414 print_qualifiers(out
, pinfo
->qualifiers
, indent
+ 2);
420 static void print_qualifiers(BIO
*out
, STACK_OF(POLICYQUALINFO
) *quals
,
423 POLICYQUALINFO
*qualinfo
;
425 for (i
= 0; i
< sk_POLICYQUALINFO_num(quals
); i
++) {
428 qualinfo
= sk_POLICYQUALINFO_value(quals
, i
);
429 switch (OBJ_obj2nid(qualinfo
->pqualid
)) {
431 BIO_printf(out
, "%*sCPS: %s", indent
, "",
432 qualinfo
->d
.cpsuri
->data
);
435 case NID_id_qt_unotice
:
436 BIO_printf(out
, "%*sUser Notice:\n", indent
, "");
437 print_notice(out
, qualinfo
->d
.usernotice
, indent
+ 2);
441 BIO_printf(out
, "%*sUnknown Qualifier: ", indent
+ 2, "");
443 i2a_ASN1_OBJECT(out
, qualinfo
->pqualid
);
449 static void print_notice(BIO
*out
, USERNOTICE
*notice
, int indent
)
452 if (notice
->noticeref
) {
454 ref
= notice
->noticeref
;
455 BIO_printf(out
, "%*sOrganization: %s\n", indent
, "",
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
++) {
462 num
= sk_ASN1_INTEGER_value(ref
->noticenos
, i
);
466 BIO_puts(out
, "(null)");
468 tmp
= i2s_ASN1_INTEGER(NULL
, num
);
479 BIO_printf(out
, "%*sExplicit Text: %s", indent
, "",
480 notice
->exptext
->data
);
483 void X509_POLICY_NODE_print(BIO
*out
, X509_POLICY_NODE
*node
, int indent
)
485 const X509_POLICY_DATA
*dat
= node
->data
;
487 BIO_printf(out
, "%*sPolicy: ", indent
, "");
489 i2a_ASN1_OBJECT(out
, dat
->valid_policy
);
491 BIO_printf(out
, "%*s%s\n", indent
+ 2, "",
492 node_data_critical(dat
) ? "Critical" : "Non Critical");
493 if (dat
->qualifier_set
) {
494 print_qualifiers(out
, dat
->qualifier_set
, indent
+ 2);
498 BIO_printf(out
, "%*sNo Qualifiers\n", indent
+ 2, "");