• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &quote, 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, &quote, 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