xref: /freebsd/crypto/openssl/crypto/x509/x_attrib.c (revision f25b8c9fb4f58cf61adb47d7570abe7caa6d385d)
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