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