1 /*
2  * Copyright (c) 2001-2019, Arm Limited and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <stdint.h>
12 
13 #include <openssl/evp.h>
14 #include <openssl/bio.h>
15 #include "common_crypto_encode.h"
16 #include "common_util_log.h"
17 
18 
19 /* header and footer of the PEM */
20 #define CC_UTIL_COMMON_PEM_HEADER       "-----BEGIN CERTIFICATE-----"
21 #define CC_UTIL_COMMON_PEM_FOOTER       "-----END CERTIFICATE-----"
22 
23 
24 #define IS_BASE64_ENCODE_VAL(val) \
25         ((((val >= '0') && (val <= '9')) || \
26          ((val >= 'A') && (val <= 'Z')) || \
27          ((val >= 'a') && (val <= 'z')) || \
28          (val == '+') || (val == '/'))?1:0)
29 
30 /**
31 * @brief Encodes data into base64 format
32 *
33 * @param[in] pBuff             - the buffer to encode
34 * @param[in] buffLen           - input buffer length
35 * @param[out] pEncBuff         - encoded buffer
36 * @param[in/out] pEncBuffLen   - encoded buffer length
37 */
38 /*********************************************************/
CC_CommonBase64Encode(uint8_t * pBuff,uint32_t buffLen,uint8_t * pEncBuff,uint32_t * pEecBuffLen)39 int32_t CC_CommonBase64Encode(uint8_t *pBuff,
40                 uint32_t  buffLen,
41                 uint8_t *pEncBuff,
42                 uint32_t *pEecBuffLen)
43 {
44     BIO *bio = NULL;
45     BIO *b64 = NULL;;
46     size_t size;
47     FILE *stream = NULL;
48     int32_t actualWritten = 0;
49     int32_t rc = 0;
50 
51     if ((NULL == pBuff) ||
52         (NULL == pEncBuff) ||
53         (NULL == pEecBuffLen) ||
54         (0 == buffLen)) {
55         UTIL_LOG_ERR("ilegal inputs\n");
56         return 1;
57     }
58     if (*pEecBuffLen < ((((buffLen*4)+2)/3)+1)) {
59         UTIL_LOG_ERR("ilegal outBuffLen %d \n", *pEecBuffLen);
60         return 1;
61     }
62 
63     memset(pEncBuff, 0, *pEecBuffLen);
64 
65     stream = fmemopen(pEncBuff, *pEecBuffLen, "w");
66     if (NULL == stream) {
67         UTIL_LOG_ERR("failed to open mem\n");
68         return 1;
69     }
70     b64 = BIO_new(BIO_f_base64());
71     if (NULL == b64) {
72         UTIL_LOG_ERR("failed to BIO_new\n");
73         rc = 1;
74         goto End_Base64Encode;
75     }
76     bio = BIO_new_fp(stream, BIO_NOCLOSE);
77     if (NULL == bio) {
78         UTIL_LOG_ERR("failed to BIO_new_fp\n");
79         rc = 1;
80         goto End_Base64Encode;
81     }
82     bio = BIO_push(b64, bio);
83     BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); //Ignore newlines - write everything in one line
84     actualWritten = BIO_write(bio, pBuff, buffLen);
85     BIO_flush(bio);
86     if (actualWritten != buffLen) {
87         UTIL_LOG_ERR("failed to BIO_write buffLen %d = actualWritten %d\n", buffLen, actualWritten);
88         rc = 1;
89         goto End_Base64Encode;
90     }
91     rc = 0;
92 
93     End_Base64Encode:
94     if (bio != NULL) { /* clears bio and b64, b64 mustn't clear explicitly*/
95         BIO_free_all(bio);
96     }
97     if (stream != NULL) {
98         fclose(stream);
99     }
100     return rc;
101 }
102 
103 
104 /**
105 * @brief Decode base64-encoded data
106 *
107 * @param[in] pEncBuff          - base64-encoded buffer
108 * @param[in] encBuffLen        - input buffer length
109 * @param[out] pDecBuff         - decoded buffer
110 * @param[in/out] pDecBuffLen   - decoded buffer length
111 */
112 /*********************************************************/
CC_CommonBase64Decode(uint8_t * pEncBuff,uint32_t encBuffLen,uint8_t * pDecBuff,uint32_t * pDecBuffLen)113 int32_t CC_CommonBase64Decode(uint8_t *pEncBuff,
114                 uint32_t  encBuffLen,
115                 uint8_t *pDecBuff,
116                 uint32_t *pDecBuffLen)
117 {
118     BIO *bio = NULL;
119     BIO *b64 = NULL;
120     int32_t actualRead = 0;
121     int32_t expDecBuffLen = 0;
122     FILE* stream = NULL;
123     int32_t padding = 0;
124     int32_t rc = 0;
125     int32_t i = 0;
126 
127     if ((NULL == pEncBuff) ||
128         (NULL == pDecBuff) ||
129         (NULL == pDecBuffLen) ||
130         (0 == encBuffLen)) {
131         UTIL_LOG_ERR("ilegal inputs\n");
132         return 1;
133     }
134 
135     UTIL_LOG_INFO("started. encBuffLen %d\n", encBuffLen);
136     /* check validity of decoded buffer length */
137     i = encBuffLen-1;
138     while (!IS_BASE64_ENCODE_VAL(pEncBuff[i])) {
139         UTIL_LOG_INFO("pEncBuff[%d] 0x%x\n", i, pEncBuff[i]);
140         padding++;
141         i--;
142     }
143     expDecBuffLen = (((encBuffLen-padding)*3)/4);
144     if (*pDecBuffLen < expDecBuffLen) {
145         UTIL_LOG_ERR("ilegal inputs outBuffLen %d expDecBuffLen %d\n", *pDecBuffLen, expDecBuffLen);
146         rc = 1;
147         goto End_Base64Decode;
148     }
149 
150     memset(pDecBuff, 0, *pDecBuffLen);
151 
152     stream = fmemopen(pEncBuff, encBuffLen, "r");
153     if (NULL == stream) {
154         UTIL_LOG_ERR("failed to open mem\n");
155         rc = 1;
156         goto End_Base64Decode;
157     }
158 
159     b64 = BIO_new(BIO_f_base64());
160     if (NULL == b64) {
161         UTIL_LOG_ERR("failed to BIO_new\n");
162         rc = 1;
163         goto End_Base64Decode;
164     }
165     bio = BIO_new_fp(stream, BIO_NOCLOSE);
166     if (NULL == bio) {
167         UTIL_LOG_ERR("failed to BIO_new_fp\n");
168         rc = 1;
169         goto End_Base64Decode;
170     }
171     bio = BIO_push(b64, bio);
172     BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); //Do not use newlines to flush buffer
173     actualRead = BIO_read(bio, pDecBuff, encBuffLen);
174     if (actualRead != expDecBuffLen) {
175         UTIL_LOG_ERR("failed to BIO_read expDecBuffLen %d = actualRead %d\n", expDecBuffLen, actualRead);
176         rc = 1;
177         goto End_Base64Decode;
178     }
179     *pDecBuffLen = actualRead;
180     rc = 0;
181 
182     End_Base64Decode:
183     if (bio != NULL) { /* clears bio and b64, b64 mustn't clear explicitly*/
184         BIO_free_all(bio);
185     }
186     if (stream != NULL) {
187         fclose(stream);
188     }
189     UTIL_LOG_INFO("rc %d\n", rc);
190     return rc;
191 }
192 
193