• 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_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