1 | /*
|
---|
2 | * Copyright 1995-2024 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/objects.h>
|
---|
13 | #include <openssl/asn1t.h>
|
---|
14 | #include <openssl/x509.h>
|
---|
15 | #include "x509_local.h"
|
---|
16 | #include <crypto/x509.h>
|
---|
17 |
|
---|
18 | /*-
|
---|
19 | * X509_ATTRIBUTE: this has the following form:
|
---|
20 | *
|
---|
21 | * typedef struct x509_attributes_st
|
---|
22 | * {
|
---|
23 | * ASN1_OBJECT *object;
|
---|
24 | * STACK_OF(ASN1_TYPE) *set;
|
---|
25 | * } X509_ATTRIBUTE;
|
---|
26 | *
|
---|
27 | */
|
---|
28 |
|
---|
29 | ASN1_SEQUENCE(X509_ATTRIBUTE) = {
|
---|
30 | ASN1_SIMPLE(X509_ATTRIBUTE, object, ASN1_OBJECT),
|
---|
31 | ASN1_SET_OF(X509_ATTRIBUTE, set, ASN1_ANY)
|
---|
32 | } ASN1_SEQUENCE_END(X509_ATTRIBUTE)
|
---|
33 |
|
---|
34 | IMPLEMENT_ASN1_FUNCTIONS(X509_ATTRIBUTE)
|
---|
35 | IMPLEMENT_ASN1_DUP_FUNCTION(X509_ATTRIBUTE)
|
---|
36 |
|
---|
37 | X509_ATTRIBUTE *X509_ATTRIBUTE_create(int nid, int atrtype, void *value)
|
---|
38 | {
|
---|
39 | X509_ATTRIBUTE *ret = NULL;
|
---|
40 | ASN1_TYPE *val = NULL;
|
---|
41 | ASN1_OBJECT *oid;
|
---|
42 |
|
---|
43 | if ((oid = OBJ_nid2obj(nid)) == NULL)
|
---|
44 | return NULL;
|
---|
45 | if ((ret = X509_ATTRIBUTE_new()) == NULL)
|
---|
46 | return NULL;
|
---|
47 | ret->object = oid;
|
---|
48 | if ((val = ASN1_TYPE_new()) == NULL)
|
---|
49 | goto err;
|
---|
50 | if (!sk_ASN1_TYPE_push(ret->set, val))
|
---|
51 | goto err;
|
---|
52 |
|
---|
53 | ASN1_TYPE_set(val, atrtype, value);
|
---|
54 | return ret;
|
---|
55 | err:
|
---|
56 | X509_ATTRIBUTE_free(ret);
|
---|
57 | ASN1_TYPE_free(val);
|
---|
58 | return NULL;
|
---|
59 | }
|
---|
60 |
|
---|
61 | static int print_hex(BIO *out, unsigned char *buf, int len)
|
---|
62 | {
|
---|
63 | int result = 1;
|
---|
64 | char *hexbuf;
|
---|
65 |
|
---|
66 | if (len == 0)
|
---|
67 | return 1;
|
---|
68 |
|
---|
69 | hexbuf = OPENSSL_buf2hexstr(buf, len);
|
---|
70 | if (hexbuf == NULL)
|
---|
71 | return 0;
|
---|
72 | result = BIO_puts(out, hexbuf) > 0;
|
---|
73 |
|
---|
74 | OPENSSL_free(hexbuf);
|
---|
75 | return result;
|
---|
76 | }
|
---|
77 |
|
---|
78 | static int print_oid(BIO *out, const ASN1_OBJECT *oid) {
|
---|
79 | const char *ln;
|
---|
80 | char objbuf[80];
|
---|
81 | int rc;
|
---|
82 |
|
---|
83 | if (OBJ_obj2txt(objbuf, sizeof(objbuf), oid, 1) <= 0)
|
---|
84 | return 0;
|
---|
85 | ln = OBJ_nid2ln(OBJ_obj2nid(oid));
|
---|
86 | rc = (ln != NULL)
|
---|
87 | ? BIO_printf(out, "%s (%s)", objbuf, ln)
|
---|
88 | : BIO_printf(out, "%s", objbuf);
|
---|
89 | return (rc >= 0);
|
---|
90 | }
|
---|
91 |
|
---|
92 | int ossl_print_attribute_value(BIO *out,
|
---|
93 | int obj_nid,
|
---|
94 | const ASN1_TYPE *av,
|
---|
95 | int indent)
|
---|
96 | {
|
---|
97 | ASN1_STRING *str;
|
---|
98 | unsigned char *value;
|
---|
99 | X509_NAME *xn = NULL;
|
---|
100 | int64_t int_val;
|
---|
101 | int ret = 1;
|
---|
102 |
|
---|
103 | switch (av->type) {
|
---|
104 | case V_ASN1_BOOLEAN:
|
---|
105 | if (av->value.boolean) {
|
---|
106 | return BIO_printf(out, "%*sTRUE", indent, "") >= 4;
|
---|
107 | } else {
|
---|
108 | return BIO_printf(out, "%*sFALSE", indent, "") >= 5;
|
---|
109 | }
|
---|
110 |
|
---|
111 | case V_ASN1_INTEGER:
|
---|
112 | case V_ASN1_ENUMERATED:
|
---|
113 | if (BIO_printf(out, "%*s", indent, "") < 0)
|
---|
114 | return 0;
|
---|
115 | if (ASN1_ENUMERATED_get_int64(&int_val, av->value.integer) > 0) {
|
---|
116 | return BIO_printf(out, "%lld", (long long int)int_val) > 0;
|
---|
117 | }
|
---|
118 | str = av->value.integer;
|
---|
119 | return print_hex(out, str->data, str->length);
|
---|
120 |
|
---|
121 | case V_ASN1_BIT_STRING:
|
---|
122 | if (BIO_printf(out, "%*s", indent, "") < 0)
|
---|
123 | return 0;
|
---|
124 | return print_hex(out, av->value.bit_string->data,
|
---|
125 | av->value.bit_string->length);
|
---|
126 |
|
---|
127 | case V_ASN1_OCTET_STRING:
|
---|
128 | case V_ASN1_VIDEOTEXSTRING:
|
---|
129 | if (BIO_printf(out, "%*s", indent, "") < 0)
|
---|
130 | return 0;
|
---|
131 | return print_hex(out, av->value.octet_string->data,
|
---|
132 | av->value.octet_string->length);
|
---|
133 |
|
---|
134 | case V_ASN1_NULL:
|
---|
135 | return BIO_printf(out, "%*sNULL", indent, "") >= 4;
|
---|
136 |
|
---|
137 | case V_ASN1_OBJECT:
|
---|
138 | if (BIO_printf(out, "%*s", indent, "") < 0)
|
---|
139 | return 0;
|
---|
140 | return print_oid(out, av->value.object);
|
---|
141 |
|
---|
142 | /*
|
---|
143 | * ObjectDescriptor is an IMPLICIT GraphicString, but GeneralString is a
|
---|
144 | * superset supported by OpenSSL, so we will use that anywhere a
|
---|
145 | * GraphicString is needed here.
|
---|
146 | */
|
---|
147 | case V_ASN1_GENERALSTRING:
|
---|
148 | case V_ASN1_GRAPHICSTRING:
|
---|
149 | case V_ASN1_OBJECT_DESCRIPTOR:
|
---|
150 | return BIO_printf(out, "%*s%.*s", indent, "",
|
---|
151 | av->value.generalstring->length,
|
---|
152 | av->value.generalstring->data) >= 0;
|
---|
153 |
|
---|
154 | /* EXTERNAL would go here. */
|
---|
155 | /* EMBEDDED PDV would go here. */
|
---|
156 |
|
---|
157 | case V_ASN1_UTF8STRING:
|
---|
158 | return BIO_printf(out, "%*s%.*s", indent, "",
|
---|
159 | av->value.utf8string->length,
|
---|
160 | av->value.utf8string->data) >= 0;
|
---|
161 |
|
---|
162 | case V_ASN1_REAL:
|
---|
163 | return BIO_printf(out, "%*sREAL", indent, "") >= 4;
|
---|
164 |
|
---|
165 | /* RELATIVE-OID would go here. */
|
---|
166 | /* TIME would go here. */
|
---|
167 |
|
---|
168 | case V_ASN1_SEQUENCE:
|
---|
169 | switch (obj_nid) {
|
---|
170 | case NID_undef: /* Unrecognized OID. */
|
---|
171 | break;
|
---|
172 | /* Attribute types with DN syntax. */
|
---|
173 | case NID_member:
|
---|
174 | case NID_roleOccupant:
|
---|
175 | case NID_seeAlso:
|
---|
176 | case NID_manager:
|
---|
177 | case NID_documentAuthor:
|
---|
178 | case NID_secretary:
|
---|
179 | case NID_associatedName:
|
---|
180 | case NID_dITRedirect:
|
---|
181 | case NID_owner:
|
---|
182 | /*
|
---|
183 | * d2i_ functions increment the ppin pointer. See doc/man3/d2i_X509.pod.
|
---|
184 | * This preserves the original pointer. We don't want to corrupt this
|
---|
185 | * value.
|
---|
186 | */
|
---|
187 | value = av->value.sequence->data;
|
---|
188 | xn = d2i_X509_NAME(NULL,
|
---|
189 | (const unsigned char **)&value,
|
---|
190 | av->value.sequence->length);
|
---|
191 | if (xn == NULL) {
|
---|
192 | BIO_puts(out, "(COULD NOT DECODE DISTINGUISHED NAME)\n");
|
---|
193 | return 0;
|
---|
194 | }
|
---|
195 | if (X509_NAME_print_ex(out, xn, indent, XN_FLAG_SEP_CPLUS_SPC) <= 0)
|
---|
196 | ret = 0;
|
---|
197 | X509_NAME_free(xn);
|
---|
198 | return ret;
|
---|
199 |
|
---|
200 | default:
|
---|
201 | break;
|
---|
202 | }
|
---|
203 | return ASN1_parse_dump(out, av->value.sequence->data,
|
---|
204 | av->value.sequence->length, indent, 1) > 0;
|
---|
205 |
|
---|
206 | case V_ASN1_SET:
|
---|
207 | return ASN1_parse_dump(out, av->value.set->data,
|
---|
208 | av->value.set->length, indent, 1) > 0;
|
---|
209 |
|
---|
210 | /*
|
---|
211 | * UTCTime ::= [UNIVERSAL 23] IMPLICIT VisibleString
|
---|
212 | * GeneralizedTime ::= [UNIVERSAL 24] IMPLICIT VisibleString
|
---|
213 | * VisibleString is a superset for NumericString, so it will work for that.
|
---|
214 | */
|
---|
215 | case V_ASN1_VISIBLESTRING:
|
---|
216 | case V_ASN1_UTCTIME:
|
---|
217 | case V_ASN1_GENERALIZEDTIME:
|
---|
218 | case V_ASN1_NUMERICSTRING:
|
---|
219 | return BIO_printf(out, "%*s%.*s", indent, "",
|
---|
220 | av->value.visiblestring->length,
|
---|
221 | av->value.visiblestring->data) >= 0;
|
---|
222 |
|
---|
223 | case V_ASN1_PRINTABLESTRING:
|
---|
224 | return BIO_printf(out, "%*s%.*s", indent, "",
|
---|
225 | av->value.printablestring->length,
|
---|
226 | av->value.printablestring->data) >= 0;
|
---|
227 |
|
---|
228 | case V_ASN1_T61STRING:
|
---|
229 | return BIO_printf(out, "%*s%.*s", indent, "",
|
---|
230 | av->value.t61string->length,
|
---|
231 | av->value.t61string->data) >= 0;
|
---|
232 |
|
---|
233 | case V_ASN1_IA5STRING:
|
---|
234 | return BIO_printf(out, "%*s%.*s", indent, "",
|
---|
235 | av->value.ia5string->length,
|
---|
236 | av->value.ia5string->data) >= 0;
|
---|
237 |
|
---|
238 | /* UniversalString would go here. */
|
---|
239 | /* CHARACTER STRING would go here. */
|
---|
240 | /* BMPString would go here. */
|
---|
241 | /* DATE would go here. */
|
---|
242 | /* TIME-OF-DAY would go here. */
|
---|
243 | /* DATE-TIME would go here. */
|
---|
244 | /* DURATION would go here. */
|
---|
245 | /* OID-IRI would go here. */
|
---|
246 | /* RELATIVE-OID-IRI would go here. */
|
---|
247 |
|
---|
248 | /* Would it be appropriate to just hexdump? */
|
---|
249 | default:
|
---|
250 | return BIO_printf(out,
|
---|
251 | "%*s<Unsupported tag %d>",
|
---|
252 | indent,
|
---|
253 | "",
|
---|
254 | av->type) >= 0;
|
---|
255 | }
|
---|
256 | }
|
---|