xref: /openssl/crypto/x509/x_attrib.c (revision 7ed6de99)
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_hex(BIO * out,unsigned char * buf,int len)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 
print_oid(BIO * out,const ASN1_OBJECT * oid)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 
ossl_print_attribute_value(BIO * out,int obj_nid,const ASN1_TYPE * av,int indent)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 }
257