summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortb <>2025-01-26 20:01:58 +0000
committertb <>2025-01-26 20:01:58 +0000
commitd2f7e48d3d75285ab819059405075d1806694766 (patch)
tree18f777cbd9c3d005bfa438b19e39b94880900d94
parent87e1f3ee1c9685a05be80a789e2b60ffe7acd7b7 (diff)
downloadopenbsd-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.h6
-rw-r--r--src/lib/libcrypto/x509/x509_obj.c221
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,
439void *X509at_get0_data_by_OBJ(STACK_OF(X509_ATTRIBUTE) *x, 441void *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
444int X509_NAME_ENTRY_add_cbb(CBB *cbb, const X509_NAME_ENTRY *ne);
445
442int X509V3_add_value(const char *name, const char *value, 446int X509V3_add_value(const char *name, const char *value,
443 STACK_OF(CONF_VALUE) **extlist); 447 STACK_OF(CONF_VALUE) **extlist);
444int X509V3_add_value_uchar(const char *name, const unsigned char *value, 448int 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
70static int
71X509_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
89static int
90X509_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
108static int
109X509_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
146int
147X509_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
70char * 158char *
71X509_NAME_oneline(const X509_NAME *a, char *buf, int len) 159X509_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
176err:
177 X509error(ERR_R_MALLOC_FAILURE);
178 if (b != NULL)
179 BUF_MEM_free(b);
180 return (NULL);
181} 196}
182LCRYPTO_ALIAS(X509_NAME_oneline); 197LCRYPTO_ALIAS(X509_NAME_oneline);