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_BSL_PEM
18 #include <stdint.h>
19 #include <string.h>
20 #include "securec.h"
21 #include "bsl_errno.h"
22 #include "bsl_err_internal.h"
23 #include "bsl_sal.h"
24 #include "bsl_base64_internal.h"
25 #include "bsl_base64.h"
26 #include "bsl_pem_local.h"
27 #include "bsl_pem_internal.h"
28
29 #define PEM_LINE_LEN 64
30
BSL_PEM_GetPemRealEncode(char ** encode,uint32_t * encodeLen,BSL_PEM_Symbol * symbol,char ** realEncode,uint32_t * realLen)31 int32_t BSL_PEM_GetPemRealEncode(char **encode, uint32_t *encodeLen, BSL_PEM_Symbol *symbol, char **realEncode,
32 uint32_t *realLen)
33 {
34 uint32_t headLen = (uint32_t)strlen(symbol->head);
35 uint32_t tailLen = (uint32_t)strlen(symbol->tail);
36 if (*encodeLen < headLen + tailLen) {
37 BSL_ERR_PUSH_ERROR(BSL_PEM_INVALID);
38 return BSL_PEM_INVALID;
39 }
40 if (!BSL_PEM_IsPemFormat(*encode, *encodeLen)) {
41 return BSL_PEM_INVALID;
42 }
43 char *begin = strstr(*encode, symbol->head);
44 if (begin == NULL) {
45 BSL_ERR_PUSH_ERROR(BSL_PEM_SYMBOL_NOT_FOUND);
46 return BSL_PEM_SYMBOL_NOT_FOUND;
47 }
48 char *end = strstr(begin + headLen, symbol->tail);
49 if (end == NULL) {
50 BSL_ERR_PUSH_ERROR(BSL_PEM_SYMBOL_NOT_FOUND);
51 return BSL_PEM_SYMBOL_NOT_FOUND;
52 }
53 *realEncode = begin + headLen;
54 *realLen = end - *realEncode;
55 *encodeLen -= (end - *encode + tailLen);
56 *encode = end + tailLen;
57 return BSL_SUCCESS;
58 }
59
60 // Obtain asn1 raw data
BSL_PEM_GetAsn1Encode(const char * encode,const uint32_t encodeLen,uint8_t ** asn1Encode,uint32_t * asn1Len)61 int32_t BSL_PEM_GetAsn1Encode(const char *encode, const uint32_t encodeLen, uint8_t **asn1Encode,
62 uint32_t *asn1Len)
63 {
64 uint32_t len = BSL_BASE64_DEC_ENOUGH_LEN(encodeLen);
65 uint8_t *asn1 = BSL_SAL_Malloc(len);
66 if (asn1 == NULL) {
67 BSL_ERR_PUSH_ERROR(BSL_MALLOC_FAIL);
68 return BSL_MALLOC_FAIL;
69 }
70 int32_t ret = BSL_BASE64_Decode(encode, encodeLen, asn1, &len);
71 if (ret != BSL_SUCCESS) {
72 BSL_ERR_PUSH_ERROR(ret);
73 BSL_SAL_Free(asn1);
74 return ret;
75 }
76 *asn1Encode = asn1;
77 *asn1Len = len;
78 return BSL_SUCCESS;
79 }
80
PemFormatBase64(char * src,uint32_t srcLen,char ** des)81 static void PemFormatBase64(char *src, uint32_t srcLen, char **des)
82 {
83 uint32_t len = srcLen;
84 char *tmp = *des;
85 while (len > PEM_LINE_LEN) {
86 *tmp++ = '\n';
87 (void)memcpy_s(tmp, PEM_LINE_LEN, src, PEM_LINE_LEN);
88 tmp += PEM_LINE_LEN;
89 src += PEM_LINE_LEN;
90 len -= PEM_LINE_LEN;
91 }
92 *tmp++ = '\n';
93 (void)memcpy_s(tmp, len, src, len);
94 tmp += len;
95 *tmp++ = '\n';
96 *des = tmp;
97 }
98
BSL_PEM_EncodeAsn1ToPem(uint8_t * asn1Encode,uint32_t asn1Len,BSL_PEM_Symbol * symbol,char ** encode,uint32_t * encodeLen)99 int32_t BSL_PEM_EncodeAsn1ToPem(uint8_t *asn1Encode, uint32_t asn1Len, BSL_PEM_Symbol *symbol,
100 char **encode, uint32_t *encodeLen)
101 {
102 int32_t ret;
103 uint32_t headLen = (uint32_t)strlen(symbol->head);
104 uint32_t tailLen = (uint32_t)strlen(symbol->tail);
105 uint32_t len = BSL_BASE64_ENC_ENOUGH_LEN(asn1Len);
106 char *buff = BSL_SAL_Malloc(len);
107 if (buff == NULL) {
108 BSL_ERR_PUSH_ERROR(BSL_MALLOC_FAIL);
109 return BSL_MALLOC_FAIL;
110 }
111 char *tmp = buff;
112 char *res = NULL;
113 do {
114 ret = BSL_BASE64_Encode(asn1Encode, asn1Len, tmp, &len);
115 if (ret != BSL_SUCCESS) {
116 BSL_ERR_PUSH_ERROR(ret);
117 break;
118 }
119 uint32_t line = (len + PEM_LINE_LEN - 1) / PEM_LINE_LEN;
120 uint32_t sumLen = line + len + headLen + tailLen + 3; // 3: \n + \n +\0
121 res = BSL_SAL_Malloc(sumLen);
122 if (res == NULL) {
123 BSL_ERR_PUSH_ERROR(BSL_MALLOC_FAIL);
124 ret = BSL_MALLOC_FAIL;
125 break;
126 }
127 char *resTmp = res;
128 (void)memcpy_s(resTmp, headLen, symbol->head, headLen);
129 resTmp += headLen;
130 PemFormatBase64(tmp, len, &resTmp);
131 (void)memcpy_s(resTmp, tailLen, symbol->tail, tailLen);
132 resTmp += tailLen;
133 *resTmp++ = '\n';
134 *resTmp++ = '\0';
135 *encode = res;
136 *encodeLen = sumLen - 1;
137 BSL_SAL_FREE(buff);
138 return BSL_SUCCESS;
139 } while (0);
140 BSL_SAL_FREE(buff);
141 BSL_SAL_FREE(res);
142 return ret;
143 }
144
BSL_PEM_DecodePemToAsn1(char ** encode,uint32_t * encodeLen,BSL_PEM_Symbol * symbol,uint8_t ** asn1Encode,uint32_t * asn1Len)145 int32_t BSL_PEM_DecodePemToAsn1(char **encode, uint32_t *encodeLen, BSL_PEM_Symbol *symbol, uint8_t **asn1Encode,
146 uint32_t *asn1Len)
147 {
148 char *nextEncode = *encode;
149 uint32_t nextEncodeLen = *encodeLen;
150 char *realEncode = NULL;
151 uint32_t realLen;
152
153 int32_t ret = BSL_PEM_GetPemRealEncode(&nextEncode, &nextEncodeLen, symbol, &realEncode, &realLen);
154 if (ret != BSL_SUCCESS) {
155 return ret;
156 }
157
158 ret = BSL_PEM_GetAsn1Encode(realEncode, realLen, asn1Encode, asn1Len);
159 if (ret != BSL_SUCCESS) {
160 BSL_ERR_PUSH_ERROR(ret);
161 return ret;
162 }
163 *encode = nextEncode;
164 *encodeLen = nextEncodeLen;
165 return BSL_SUCCESS;
166 }
167
168 /**
169 * reference rfc7468
170 * Textual encoding begins with a line comprising "-----BEGIN ", a label, and "-----",
171 * and ends with a line comprising "-----END ", a label, and "-----".
172 */
BSL_PEM_IsPemFormat(char * encode,uint32_t encodeLen)173 bool BSL_PEM_IsPemFormat(char *encode, uint32_t encodeLen)
174 {
175 if (encode == NULL || encodeLen < (BSL_PEM_BEGIN_STR_LEN + BSL_PEM_END_STR_LEN
176 + 2 * BSL_PEM_SHORT_DASH_STR_LEN)) {
177 return false;
178 }
179 // match "-----BEGIN"
180 char *begin = strstr(encode, BSL_PEM_BEGIN_STR);
181 if (begin == NULL) {
182 return false;
183 }
184 char *tmp = (char *)encode + BSL_PEM_BEGIN_STR_LEN;
185 // match "-----"
186 begin = strstr(tmp, BSL_PEM_SHORT_DASH_STR);
187 if (begin == NULL) {
188 return false;
189 }
190
191 tmp = begin + BSL_PEM_SHORT_DASH_STR_LEN;
192
193 // match "-----END"
194 begin = strstr(tmp, BSL_PEM_END_STR);
195 if (begin == NULL) {
196 return false;
197 }
198 tmp = begin + BSL_PEM_END_STR_LEN;
199
200 // match "-----"
201 if (strstr(tmp, BSL_PEM_SHORT_DASH_STR) == NULL) {
202 return false;
203 }
204 return true;
205 }
206
207 typedef struct {
208 char *type;
209 BSL_PEM_Symbol symbol;
210 } PemHeaderInfo;
211
212 static PemHeaderInfo g_pemHeaderInfo[] = {
213 {"PRIKEY_RSA", {BSL_PEM_RSA_PRI_KEY_BEGIN_STR, BSL_PEM_RSA_PRI_KEY_END_STR}},
214 {"PRIKEY_ECC", {BSL_PEM_EC_PRI_KEY_BEGIN_STR, BSL_PEM_EC_PRI_KEY_END_STR}},
215 {"PRIKEY_PKCS8_UNENCRYPT", {BSL_PEM_PRI_KEY_BEGIN_STR, BSL_PEM_PRI_KEY_END_STR}},
216 {"PRIKEY_PKCS8_ENCRYPT", {BSL_PEM_P8_PRI_KEY_BEGIN_STR, BSL_PEM_P8_PRI_KEY_END_STR}},
217 {"PUBKEY_SUBKEY", {BSL_PEM_PUB_KEY_BEGIN_STR, BSL_PEM_PUB_KEY_END_STR}},
218 {"PUBKEY_RSA", {BSL_PEM_RSA_PUB_KEY_BEGIN_STR, BSL_PEM_RSA_PUB_KEY_END_STR}},
219 {"CERT", {BSL_PEM_CERT_BEGIN_STR, BSL_PEM_CERT_END_STR}},
220 {"CRL", {BSL_PEM_CRL_BEGIN_STR, BSL_PEM_CRL_END_STR}},
221 {"CSR", {BSL_PEM_CERT_REQ_BEGIN_STR, BSL_PEM_CERT_REQ_END_STR}},
222 };
223
BSL_PEM_GetSymbolAndType(char * encode,uint32_t encodeLen,BSL_PEM_Symbol * symbol,char ** type)224 int32_t BSL_PEM_GetSymbolAndType(char *encode, uint32_t encodeLen, BSL_PEM_Symbol *symbol, char **type)
225 {
226 if (symbol == NULL || type == NULL) {
227 BSL_ERR_PUSH_ERROR(BSL_NULL_INPUT);
228 return BSL_NULL_INPUT;
229 }
230
231 if (!BSL_PEM_IsPemFormat(encode, encodeLen)) {
232 BSL_ERR_PUSH_ERROR(BSL_PEM_INVALID);
233 return BSL_PEM_INVALID;
234 }
235 for (uint32_t i = 0; i < sizeof(g_pemHeaderInfo) / sizeof(g_pemHeaderInfo[0]); i++) {
236 char *beginMarker = strstr(encode, g_pemHeaderInfo[i].symbol.head);
237 if (beginMarker != NULL) {
238 char *endMarker = strstr(beginMarker + strlen(g_pemHeaderInfo[i].symbol.head),
239 g_pemHeaderInfo[i].symbol.tail);
240 if (endMarker != NULL) {
241 symbol->head = g_pemHeaderInfo[i].symbol.head;
242 symbol->tail = g_pemHeaderInfo[i].symbol.tail;
243 *type = g_pemHeaderInfo[i].type;
244 return BSL_SUCCESS;
245 }
246 }
247 }
248
249 BSL_ERR_PUSH_ERROR(BSL_PEM_SYMBOL_NOT_FOUND);
250 return BSL_PEM_SYMBOL_NOT_FOUND;
251 }
252
253 #endif /* HITLS_BSL_PEM */
254