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