diff options
author | tb <> | 2025-01-26 20:01:58 +0000 |
---|---|---|
committer | tb <> | 2025-01-26 20:01:58 +0000 |
commit | d2f7e48d3d75285ab819059405075d1806694766 (patch) | |
tree | 18f777cbd9c3d005bfa438b19e39b94880900d94 | |
parent | 87e1f3ee1c9685a05be80a789e2b60ffe7acd7b7 (diff) | |
download | openbsd-d2f7e48d3d75285ab819059405075d1806694766.tar.gz openbsd-d2f7e48d3d75285ab819059405075d1806694766.tar.bz2 openbsd-d2f7e48d3d75285ab819059405075d1806694766.zip |
Rewrite X509_NAME_ENTRY_oneline() using CBB and CBS
This splits the horrid spaghetti into a few relatively straightforward
helpers which do one thing at a time. There are still some spectacular
dances around ASN1_GENERALSTRING, but let's blame that one on X.500.
In brief, X509_NAME_ENTRY_oneline() iterates over the name entries, and
writes out a line /name1=value1,/name2=value2,... which you may have seen
variations of in issuer or subject output.
The name is the short name or the long name or the textual representation
of the OID (truncated to 79 characters) and the value is a string where
printable ASCII characters are represented as themselves and otherwise as
hexadecimal digits preceded by \x. Except for GENERALSTRING, where the four
octet representation is shortened to single-octet representation if none of
the top three octets in the entire string is populated.
It's the mother of all pretty things. But, hey, you could do worse and try
to parse this garbage...
ok jsing
-rw-r--r-- | src/lib/libcrypto/x509/x509_local.h | 6 | ||||
-rw-r--r-- | src/lib/libcrypto/x509/x509_obj.c | 221 |
2 files changed, 123 insertions, 104 deletions
diff --git a/src/lib/libcrypto/x509/x509_local.h b/src/lib/libcrypto/x509/x509_local.h index e4d4b4ddd0..5240db1489 100644 --- a/src/lib/libcrypto/x509/x509_local.h +++ b/src/lib/libcrypto/x509/x509_local.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: x509_local.h,v 1.33 2024/12/04 20:07:16 tb Exp $ */ | 1 | /* $OpenBSD: x509_local.h,v 1.34 2025/01/26 20:01:58 tb Exp $ */ |
2 | /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL | 2 | /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL |
3 | * project 2013. | 3 | * project 2013. |
4 | */ | 4 | */ |
@@ -61,6 +61,8 @@ | |||
61 | 61 | ||
62 | #include <openssl/x509v3.h> | 62 | #include <openssl/x509v3.h> |
63 | 63 | ||
64 | #include "bytestring.h" | ||
65 | |||
64 | __BEGIN_HIDDEN_DECLS | 66 | __BEGIN_HIDDEN_DECLS |
65 | 67 | ||
66 | #define TS_HASH_EVP EVP_sha1() | 68 | #define TS_HASH_EVP EVP_sha1() |
@@ -439,6 +441,8 @@ STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr_by_txt(STACK_OF(X509_ATTRIBUTE) **x, | |||
439 | void *X509at_get0_data_by_OBJ(STACK_OF(X509_ATTRIBUTE) *x, | 441 | void *X509at_get0_data_by_OBJ(STACK_OF(X509_ATTRIBUTE) *x, |
440 | const ASN1_OBJECT *obj, int lastpos, int type); | 442 | const ASN1_OBJECT *obj, int lastpos, int type); |
441 | 443 | ||
444 | int X509_NAME_ENTRY_add_cbb(CBB *cbb, const X509_NAME_ENTRY *ne); | ||
445 | |||
442 | int X509V3_add_value(const char *name, const char *value, | 446 | int X509V3_add_value(const char *name, const char *value, |
443 | STACK_OF(CONF_VALUE) **extlist); | 447 | STACK_OF(CONF_VALUE) **extlist); |
444 | int X509V3_add_value_uchar(const char *name, const unsigned char *value, | 448 | int X509V3_add_value_uchar(const char *name, const unsigned char *value, |
diff --git a/src/lib/libcrypto/x509/x509_obj.c b/src/lib/libcrypto/x509/x509_obj.c index ea4ae6b98a..25cca54bdb 100644 --- a/src/lib/libcrypto/x509/x509_obj.c +++ b/src/lib/libcrypto/x509/x509_obj.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: x509_obj.c,v 1.22 2023/02/16 08:38:17 tb Exp $ */ | 1 | /* $OpenBSD: x509_obj.c,v 1.23 2025/01/26 20:01:58 tb Exp $ */ |
2 | /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) | 2 | /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) |
3 | * All rights reserved. | 3 | * All rights reserved. |
4 | * | 4 | * |
@@ -67,116 +67,131 @@ | |||
67 | 67 | ||
68 | #include "x509_local.h" | 68 | #include "x509_local.h" |
69 | 69 | ||
70 | static int | ||
71 | X509_NAME_ENTRY_add_object_cbb(CBB *cbb, const ASN1_OBJECT *aobj) | ||
72 | { | ||
73 | const char *str; | ||
74 | char buf[80]; | ||
75 | int nid; | ||
76 | |||
77 | /* Prefer SN over LN, and fall back to textual representation of OID. */ | ||
78 | if ((nid = OBJ_obj2nid(aobj)) != NID_undef) { | ||
79 | if ((str = OBJ_nid2sn(nid)) != NULL) | ||
80 | return CBB_add_bytes(cbb, str, strlen(str)); | ||
81 | if ((str = OBJ_nid2ln(nid)) != NULL) | ||
82 | return CBB_add_bytes(cbb, str, strlen(str)); | ||
83 | } | ||
84 | if (OBJ_obj2txt(buf, sizeof(buf), aobj, 1) == 0) | ||
85 | return 0; | ||
86 | return CBB_add_bytes(cbb, buf, strlen(buf)); | ||
87 | } | ||
88 | |||
89 | static int | ||
90 | X509_NAME_ENTRY_add_u8_cbb(CBB *cbb, uint8_t u8) | ||
91 | { | ||
92 | static const char hex[] = "0123456789ABCDEF"; | ||
93 | |||
94 | if (' ' <= u8 && u8 <= '~') | ||
95 | return CBB_add_u8(cbb, u8); | ||
96 | |||
97 | if (!CBB_add_u8(cbb, '\\')) | ||
98 | return 0; | ||
99 | if (!CBB_add_u8(cbb, 'x')) | ||
100 | return 0; | ||
101 | if (!CBB_add_u8(cbb, hex[u8 >> 4])) | ||
102 | return 0; | ||
103 | if (!CBB_add_u8(cbb, hex[u8 & 0xf])) | ||
104 | return 0; | ||
105 | return 1; | ||
106 | } | ||
107 | |||
108 | static int | ||
109 | X509_NAME_ENTRY_add_value_cbb(CBB *cbb, const ASN1_STRING *astr) | ||
110 | { | ||
111 | CBS cbs; | ||
112 | uint8_t u8; | ||
113 | size_t i; | ||
114 | int mask[4] = { 1, 1, 1, 1 }; | ||
115 | |||
116 | if (astr->type == V_ASN1_GENERALSTRING && astr->length % 4 == 0) { | ||
117 | int gs_mask[4] = { 0, 0, 0, 0 }; | ||
118 | |||
119 | i = 0; | ||
120 | CBS_init(&cbs, astr->data, astr->length); | ||
121 | while (CBS_len(&cbs) > 0) { | ||
122 | if (!CBS_get_u8(&cbs, &u8)) | ||
123 | return 0; | ||
124 | |||
125 | gs_mask[i++ & 0x3] |= u8; | ||
126 | } | ||
127 | |||
128 | if (gs_mask[0] == 0 && gs_mask[1] == 0 && gs_mask[2] == 0) | ||
129 | mask[0] = mask[1] = mask[2] = 0; | ||
130 | } | ||
131 | |||
132 | i = 0; | ||
133 | CBS_init(&cbs, astr->data, astr->length); | ||
134 | while (CBS_len(&cbs) > 0) { | ||
135 | if (!CBS_get_u8(&cbs, &u8)) | ||
136 | return 0; | ||
137 | if (mask[i++ & 0x3] == 0) | ||
138 | continue; | ||
139 | if (!X509_NAME_ENTRY_add_u8_cbb(cbb, u8)) | ||
140 | return 0; | ||
141 | } | ||
142 | |||
143 | return 1; | ||
144 | } | ||
145 | |||
146 | int | ||
147 | X509_NAME_ENTRY_add_cbb(CBB *cbb, const X509_NAME_ENTRY *ne) | ||
148 | { | ||
149 | if (!X509_NAME_ENTRY_add_object_cbb(cbb, ne->object)) | ||
150 | return 0; | ||
151 | if (!CBB_add_u8(cbb, '=')) | ||
152 | return 0; | ||
153 | if (!X509_NAME_ENTRY_add_value_cbb(cbb, ne->value)) | ||
154 | return 0; | ||
155 | return 1; | ||
156 | } | ||
157 | |||
70 | char * | 158 | char * |
71 | X509_NAME_oneline(const X509_NAME *a, char *buf, int len) | 159 | X509_NAME_oneline(const X509_NAME *a, char *buf, int len) |
72 | { | 160 | { |
73 | X509_NAME_ENTRY *ne; | 161 | CBB cbb; |
162 | const X509_NAME_ENTRY *ne; | ||
163 | uint8_t *line = NULL; | ||
164 | size_t line_len = 0; | ||
74 | int i; | 165 | int i; |
75 | int n, lold, l, l1, l2, num, j, type; | 166 | |
76 | const char *s; | 167 | if (!CBB_init(&cbb, 0)) |
77 | char *p; | 168 | goto err; |
78 | unsigned char *q; | 169 | |
79 | BUF_MEM *b = NULL; | 170 | for (i = 0; i < sk_X509_NAME_ENTRY_num(a->entries); i++) { |
80 | static const char hex[17] = "0123456789ABCDEF"; | 171 | ne = sk_X509_NAME_ENTRY_value(a->entries, i); |
81 | int gs_doit[4]; | 172 | if (!CBB_add_u8(&cbb, '/')) |
82 | char tmp_buf[80]; | ||
83 | |||
84 | if (buf == NULL) { | ||
85 | if ((b = BUF_MEM_new()) == NULL) | ||
86 | goto err; | 173 | goto err; |
87 | if (!BUF_MEM_grow(b, 200)) | 174 | if (!X509_NAME_ENTRY_add_cbb(&cbb, ne)) |
88 | goto err; | 175 | goto err; |
89 | b->data[0] = '\0'; | ||
90 | len = 200; | ||
91 | } | ||
92 | if (a == NULL) { | ||
93 | if (b) { | ||
94 | buf = b->data; | ||
95 | free(b); | ||
96 | } | ||
97 | strlcpy(buf, "NO X509_NAME", len); | ||
98 | return buf; | ||
99 | } | 176 | } |
100 | 177 | ||
101 | len--; /* space for '\0' */ | 178 | if (!CBB_add_u8(&cbb, '\0')) |
102 | l = 0; | 179 | goto err; |
103 | for (i = 0; i < sk_X509_NAME_ENTRY_num(a->entries); i++) { | ||
104 | ne = sk_X509_NAME_ENTRY_value(a->entries, i); | ||
105 | n = OBJ_obj2nid(ne->object); | ||
106 | if ((n == NID_undef) || ((s = OBJ_nid2sn(n)) == NULL)) { | ||
107 | i2t_ASN1_OBJECT(tmp_buf, sizeof(tmp_buf), ne->object); | ||
108 | s = tmp_buf; | ||
109 | } | ||
110 | l1 = strlen(s); | ||
111 | |||
112 | type = ne->value->type; | ||
113 | num = ne->value->length; | ||
114 | q = ne->value->data; | ||
115 | if ((type == V_ASN1_GENERALSTRING) && ((num % 4) == 0)) { | ||
116 | gs_doit[0] = gs_doit[1] = gs_doit[2] = gs_doit[3] = 0; | ||
117 | for (j = 0; j < num; j++) | ||
118 | if (q[j] != 0) | ||
119 | gs_doit[j & 3] = 1; | ||
120 | |||
121 | if (gs_doit[0]|gs_doit[1]|gs_doit[2]) | ||
122 | gs_doit[0] = gs_doit[1] = gs_doit[2] = gs_doit[3] = 1; | ||
123 | else { | ||
124 | gs_doit[0] = gs_doit[1] = gs_doit[2] = 0; | ||
125 | gs_doit[3] = 1; | ||
126 | } | ||
127 | } else | ||
128 | gs_doit[0] = gs_doit[1] = gs_doit[2] = gs_doit[3] = 1; | ||
129 | |||
130 | for (l2 = j=0; j < num; j++) { | ||
131 | if (!gs_doit[j&3]) | ||
132 | continue; | ||
133 | l2++; | ||
134 | if ((q[j] < ' ') || (q[j] > '~')) | ||
135 | l2 += 3; | ||
136 | } | ||
137 | 180 | ||
138 | lold = l; | 181 | if (!CBB_finish(&cbb, &line, &line_len)) |
139 | l += 1 + l1 + 1 + l2; | 182 | goto err; |
140 | if (b != NULL) { | 183 | |
141 | if (!BUF_MEM_grow(b, l + 1)) | 184 | if (buf == NULL) |
142 | goto err; | 185 | return line; |
143 | p = &(b->data[lold]); | 186 | |
144 | } else if (l > len) { | 187 | strlcpy(buf, line, len); |
145 | break; | 188 | free(line); |
146 | } else | 189 | |
147 | p = &(buf[lold]); | 190 | return buf; |
148 | *(p++) = '/'; | 191 | |
149 | memcpy(p, s, l1); | 192 | err: |
150 | p += l1; | 193 | CBB_cleanup(&cbb); |
151 | *(p++) = '='; | 194 | |
152 | q = ne->value->data; | 195 | return NULL; |
153 | for (j = 0; j < num; j++) { | ||
154 | if (!gs_doit[j & 3]) | ||
155 | continue; | ||
156 | n = q[j]; | ||
157 | if ((n < ' ') || (n > '~')) { | ||
158 | *(p++) = '\\'; | ||
159 | *(p++) = 'x'; | ||
160 | *(p++) = hex[(n >> 4) & 0x0f]; | ||
161 | *(p++) = hex[n & 0x0f]; | ||
162 | } else | ||
163 | *(p++) = n; | ||
164 | } | ||
165 | *p = '\0'; | ||
166 | } | ||
167 | if (b != NULL) { | ||
168 | p = b->data; | ||
169 | free(b); | ||
170 | } else | ||
171 | p = buf; | ||
172 | if (i == 0) | ||
173 | *p = '\0'; | ||
174 | return (p); | ||
175 | |||
176 | err: | ||
177 | X509error(ERR_R_MALLOC_FAILURE); | ||
178 | if (b != NULL) | ||
179 | BUF_MEM_free(b); | ||
180 | return (NULL); | ||
181 | } | 196 | } |
182 | LCRYPTO_ALIAS(X509_NAME_oneline); | 197 | LCRYPTO_ALIAS(X509_NAME_oneline); |