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