1 /*
2 * This file is part of the openHiTLS project.
3 *
4 * openHiTLS is licensed under the Mulan PSL v2.
5 * You can use this software according to the terms and conditions of the Mulan PSL v2.
6 * You may obtain a copy of Mulan PSL v2 at:
7 *
8 * http://license.coscl.org.cn/MulanPSL2
9 *
10 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
11 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
12 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
13 * See the Mulan PSL v2 for more details.
14 */
15
16 #include "hitls_build.h"
17 #ifdef HITLS_PKI_INFO
18 #include <stdbool.h>
19 #include <stdint.h>
20 #include <string.h>
21 #include "bsl_list.h"
22 #include "bsl_uio.h"
23 #include "bsl_asn1.h"
24 #include "bsl_obj_internal.h"
25 #include "bsl_err_internal.h"
26 #include "hitls_x509_local.h"
27 #include "hitls_pki_errno.h"
28 #include "hitls_print_local.h"
29
30 static uint32_t g_nameFlag = HITLS_PKI_PRINT_DN_RFC2253;
31
32 static char g_rfc2253Escape[] = {',', '+', '"', '\\', '<', '>', ';'};
33
34 #define RFC2253_ESCAPE_CHAR_CNT (sizeof(g_rfc2253Escape) / sizeof(g_rfc2253Escape[0]))
35
GetPrefixFmt(bool preLayerIs2,bool isFirst)36 static char *GetPrefixFmt(bool preLayerIs2, bool isFirst)
37 {
38 if (preLayerIs2) {
39 if (g_nameFlag == HITLS_PKI_PRINT_DN_RFC2253) {
40 return "+%s=";
41 }
42 return " + %s = ";
43 }
44 if (g_nameFlag == HITLS_PKI_PRINT_DN_RFC2253) {
45 return isFirst ? "%s=" : ",%s=";
46 }
47
48 if (g_nameFlag == HITLS_PKI_PRINT_DN_ONELINE) {
49 return isFirst ? "%s = " : ", %s = ";
50 }
51 return "%s = "; // multiline
52 }
53
NeedQuote(BSL_ASN1_Buffer * value)54 static bool NeedQuote(BSL_ASN1_Buffer *value)
55 {
56 if (g_nameFlag != HITLS_PKI_PRINT_DN_ONELINE) {
57 return false;
58 }
59 for (uint32_t i = 0; i < value->len; i++) {
60 if (i == 0 && (value->buff[i] == '#' || value->buff[i] == ' ')) {
61 return true;
62 }
63 if (value->buff[i] == ',' || value->buff[i] == '<' || value->buff[i] == '>') {
64 return true;
65 }
66 }
67 return false;
68 }
69
CharInList(char c,char * list,uint32_t listSize)70 static bool CharInList(char c, char *list, uint32_t listSize)
71 {
72 for (uint32_t i = 0; i < listSize; i++) {
73 if (c == list[i]) {
74 return true;
75 }
76 }
77 return false;
78 }
79
PrintDnNameValue(BSL_ASN1_Buffer * value,BSL_UIO * uio)80 static int32_t PrintDnNameValue(BSL_ASN1_Buffer *value, BSL_UIO *uio)
81 {
82 uint8_t *cur = value->buff;
83 uint8_t *end = value->buff + value->len;
84 char quote = '"';
85 bool needQuote = NeedQuote(value);
86 if (needQuote && BSL_ASN1_PrintfBuff(0, uio, "e, 1) != BSL_SUCCESS) {
87 BSL_ERR_PUSH_ERROR(HITLS_PRINT_ERR_DNNAME_VALUE);
88 return HITLS_PRINT_ERR_DNNAME_VALUE;
89 }
90 char c;
91 char *fmt;
92 int32_t ret;
93 while (cur != end) {
94 c = *cur;
95 /*
96 * RFC2253: section 2.4
97 * Characters that need escaping:
98 * (1) A space or "#" character occurring at the beginning of the string
99 * (2) A space character occurring at the end of the string
100 * (3) One of the characters: ",", "+", """, "\", "<", ">", ";"
101 */
102 fmt = NULL;
103 if (c < ' ' || c > '~') { // control character
104 fmt = "\\%02X";
105 } else if (g_nameFlag == HITLS_PKI_PRINT_DN_RFC2253) {
106 if ((cur == value->buff && (c == ' ' || c == '#')) || // (1)
107 (cur + 1 == end && c == ' ') || // (2)
108 CharInList(c, g_rfc2253Escape, RFC2253_ESCAPE_CHAR_CNT)) { // (3)
109 fmt = "\\%c";
110 }
111 } else if (needQuote && c == '"') {
112 fmt = "\\%c";
113 }
114 ret = fmt == NULL ? BSL_ASN1_PrintfBuff(0, uio, &c, 1) : BSL_ASN1_Printf(0, uio, fmt, c);
115 if (ret != BSL_SUCCESS) {
116 BSL_ERR_PUSH_ERROR(HITLS_PRINT_ERR_DNNAME_VALUE);
117 return HITLS_PRINT_ERR_DNNAME_VALUE;
118 }
119 cur++;
120 }
121 if (needQuote && BSL_ASN1_PrintfBuff(0, uio, "e, 1) != BSL_SUCCESS) {
122 BSL_ERR_PUSH_ERROR(HITLS_PRINT_ERR_DNNAME_VALUE);
123 return HITLS_PRINT_ERR_DNNAME_VALUE;
124 }
125 return HITLS_PKI_SUCCESS;
126 }
127
PrintDn(uint32_t layer,BSL_ASN1_List * nameList,bool newLine,BSL_UIO * uio)128 static int32_t PrintDn(uint32_t layer, BSL_ASN1_List *nameList, bool newLine, BSL_UIO *uio)
129 {
130 BslOidString oid = {0};
131 const char *oidName = NULL;
132 bool preLayerIs2 = false;
133 int8_t namePosFlag = -1; // -1: not start; 0: first; 1: other
134 int32_t ret;
135 HITLS_X509_NameNode *name = g_nameFlag == HITLS_PKI_PRINT_DN_RFC2253 ?
136 BSL_LIST_GET_LAST(nameList) : BSL_LIST_GET_FIRST(nameList);
137 while (name != NULL) {
138 if (name->layer == 1) {
139 preLayerIs2 = false;
140 name = g_nameFlag == HITLS_PKI_PRINT_DN_RFC2253 ? BSL_LIST_GET_PREV(nameList) :
141 BSL_LIST_GET_NEXT(nameList);
142 continue;
143 }
144 namePosFlag = namePosFlag == -1 ? 0 : 1;
145 oid.octs = (char *)name->nameType.buff;
146 oid.octetLen = name->nameType.len;
147 oidName = BSL_OBJ_GetOidNameFromOid(&oid); // multiline format use long name, but now only support short name
148 if (oidName == NULL) {
149 oidName = "Unknown";
150 }
151 if (g_nameFlag == HITLS_PKI_PRINT_DN_MULTILINE) {
152 if (namePosFlag == 0) {
153 ret = BSL_ASN1_PrintfBuff(layer, uio, NULL, 0);
154 } else if (!preLayerIs2) {
155 ret = BSL_ASN1_PrintfBuff(0, uio, "\n", strlen("\n")) || BSL_ASN1_PrintfBuff(layer, uio, NULL, 0);
156 }
157 if (ret != BSL_SUCCESS) {
158 BSL_ERR_PUSH_ERROR(HITLS_PRINT_ERR_DNNAME);
159 return HITLS_PRINT_ERR_DNNAME;
160 }
161 }
162 /* print type */
163 if (BSL_ASN1_Printf(0, uio, GetPrefixFmt(preLayerIs2, namePosFlag == 0), oidName) != BSL_SUCCESS) {
164 BSL_ERR_PUSH_ERROR(HITLS_PRINT_ERR_DNNAME);
165 return HITLS_PRINT_ERR_DNNAME;
166 }
167 /* print value */
168 if (name->nameValue.buff != NULL && name->nameValue.len != 0) {
169 ret = PrintDnNameValue(&name->nameValue, uio);
170 if (ret != HITLS_PKI_SUCCESS) {
171 return ret;
172 }
173 }
174 preLayerIs2 = name->layer != 1;
175 name = g_nameFlag == HITLS_PKI_PRINT_DN_RFC2253 ? BSL_LIST_GET_PREV(nameList) :
176 BSL_LIST_GET_NEXT(nameList);
177 }
178 if (newLine) {
179 return BSL_ASN1_PrintfBuff(0, uio, "\n", strlen("\n")) != 0 ? HITLS_PRINT_ERR_DNNAME : HITLS_PKI_SUCCESS;
180 }
181 return HITLS_PKI_SUCCESS;
182 }
183
SetPrintFlag(void * val,uint32_t valLen)184 static int32_t SetPrintFlag(void *val, uint32_t valLen)
185 {
186 if (val == NULL || valLen != sizeof(uint32_t)) {
187 BSL_ERR_PUSH_ERROR(HITLS_X509_ERR_INVALID_PARAM);
188 return HITLS_X509_ERR_INVALID_PARAM;
189 }
190 g_nameFlag = *(uint32_t *)val;
191 return HITLS_PKI_SUCCESS;
192 }
193
HITLS_PKI_PrintCtrl(int32_t cmd,void * val,uint32_t valLen,BSL_UIO * uio)194 int32_t HITLS_PKI_PrintCtrl(int32_t cmd, void *val, uint32_t valLen, BSL_UIO *uio)
195 {
196 if (cmd == HITLS_PKI_SET_PRINT_FLAG) {
197 return SetPrintFlag(val, valLen);
198 }
199 if (val == NULL || uio == NULL) {
200 BSL_ERR_PUSH_ERROR(HITLS_X509_ERR_INVALID_PARAM);
201 return HITLS_X509_ERR_INVALID_PARAM;
202 }
203 switch (cmd) {
204 case HITLS_PKI_PRINT_DN:
205 if (valLen != sizeof(BslList)) {
206 BSL_ERR_PUSH_ERROR(HITLS_X509_ERR_INVALID_PARAM);
207 return HITLS_X509_ERR_INVALID_PARAM;
208 }
209 return PrintDn(g_nameFlag == HITLS_PKI_PRINT_DN_MULTILINE ? 1 : 0, val, false, uio);
210 default:
211 BSL_ERR_PUSH_ERROR(HITLS_X509_ERR_INVALID_PARAM);
212 return HITLS_X509_ERR_INVALID_PARAM;
213 }
214 }
215 #endif // HITLS_PKI_INFO
216