1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "x509_distinguished_name_openssl.h"
17
18 #include <securec.h>
19 #include <openssl/x509.h>
20 #include <openssl/x509v3.h>
21 #include <openssl/evp.h>
22 #include <openssl/pem.h>
23
24 #include "config.h"
25 #include "cf_log.h"
26 #include "cf_memory.h"
27 #include "cf_result.h"
28 #include "cf_blob.h"
29 #include "result.h"
30 #include "utils.h"
31 #include "x509_distinguished_name_spi.h"
32 #include "certificate_openssl_common.h"
33
34 #define X509_DISTINGUISHED_NAME_OPENSSL_CLASS "X509DistinguishedNameOpensslClass"
35
GetX509DistinguishedNameClass(void)36 static const char *GetX509DistinguishedNameClass(void)
37 {
38 return X509_DISTINGUISHED_NAME_OPENSSL_CLASS;
39 }
40
DestroyX509DistinguishedNameOpenssl(CfObjectBase * self)41 static void DestroyX509DistinguishedNameOpenssl(CfObjectBase *self)
42 {
43 if (self == NULL) {
44 return;
45 }
46 if (!CfIsClassMatch(self, GetX509DistinguishedNameClass())) {
47 LOGE("Input wrong class type!");
48 return;
49 }
50 HcfX509DistinguishedNameOpensslImpl *realName = (HcfX509DistinguishedNameOpensslImpl *)self;
51 X509_NAME_free(realName->name);
52 realName->name = NULL;
53 CfFree(realName);
54 }
55
GetEncodeOpenssl(HcfX509DistinguishedNameSpi * self,CfEncodingBlob * out)56 static CfResult GetEncodeOpenssl(HcfX509DistinguishedNameSpi *self, CfEncodingBlob *out)
57 {
58 if ((self == NULL) || (out == NULL)) {
59 LOGE("The input data is null!");
60 return CF_INVALID_PARAMS;
61 }
62 if (!CfIsClassMatch((CfObjectBase *)self, GetX509DistinguishedNameClass())) {
63 LOGE("Input wrong class type!");
64 return CF_INVALID_PARAMS;
65 }
66 HcfX509DistinguishedNameOpensslImpl *realName = (HcfX509DistinguishedNameOpensslImpl *)self;
67 size_t len = 0;
68 const unsigned char *p = NULL;
69 if (X509_NAME_get0_der(realName->name, &p, &len) == 1) {
70 out->data = (uint8_t *)CfMalloc((uint32_t)len, 0);
71 if (out->data == NULL) {
72 LOGE("Failed to malloc for encoded data!");
73 return CF_ERR_MALLOC;
74 }
75 if (memcpy_s(out->data, len, p, len) != EOK) {
76 LOGE("memcpy_s data to buffer failed!");
77 CfFree(out->data);
78 out->data = NULL;
79 return CF_ERR_COPY;
80 }
81
82 out->len = len;
83 out->encodingFormat = CF_FORMAT_DER;
84 return CF_SUCCESS;
85 }
86
87 LOGE("X509_NAME_get0_der error!");
88 return CF_ERR_CRYPTO_OPERATION;
89 }
90
GetDataByEntryOpenssl(int32_t count,CfArray * outArr,X509_NAME_ENTRY ** neArr)91 static CfResult GetDataByEntryOpenssl(int32_t count, CfArray *outArr, X509_NAME_ENTRY **neArr)
92 {
93 if (count <= 0 || outArr == NULL || *neArr == NULL) {
94 LOGE("GetDataByEntryOpenssl data is null!");
95 return CF_INVALID_PARAMS;
96 }
97
98 outArr->data = (CfBlob *)CfMalloc(count * sizeof(CfBlob), 0);
99 if (outArr->data == NULL) {
100 LOGE("CfMalloc error");
101 return CF_ERR_MALLOC;
102 }
103 outArr->count = count;
104 for (int i = 0; i < count; ++i) {
105 ASN1_STRING *str = X509_NAME_ENTRY_get_data(neArr[i]);
106 unsigned char *p = ASN1_STRING_data(str);
107 int len = ASN1_STRING_length(str);
108 if (len <= 0) {
109 LOGE("ASN1_STRING_length error");
110 CfArrayDataClearAndFree(outArr);
111 return CF_ERR_CRYPTO_OPERATION;
112 }
113 CfResult res = DeepCopyDataToOut((const char *)p, len, &(outArr->data[i]));
114 if (res != CF_SUCCESS) {
115 LOGE("DeepCopyDataToOut error");
116 CfArrayDataClearAndFree(outArr);
117 return res;
118 }
119 }
120 return CF_SUCCESS;
121 }
122
GetNameTypeByOpenssl(HcfX509DistinguishedNameOpensslImpl * realName,CfBlob * type,CfArray * outArr)123 static CfResult GetNameTypeByOpenssl(HcfX509DistinguishedNameOpensslImpl *realName, CfBlob *type, CfArray *outArr)
124 {
125 if (realName == NULL || type == NULL || outArr == NULL) {
126 LOGE("The input data is null!");
127 return CF_INVALID_PARAMS;
128 }
129
130 if (type->size < 1) {
131 LOGE("The input type size is zero!");
132 return CF_INVALID_PARAMS;
133 }
134 X509_NAME_ENTRY **neArr = (X509_NAME_ENTRY **)CfMalloc(
135 X509_NAME_entry_count(realName->name) * sizeof(X509_NAME_ENTRY *), 0);
136 if (neArr == NULL) {
137 LOGE("CfMalloc error");
138 return CF_ERR_MALLOC;
139 }
140
141 int j = 0;
142 for (int i = 0; i < X509_NAME_entry_count(realName->name); ++i) {
143 X509_NAME_ENTRY *ne = X509_NAME_get_entry(realName->name, i);
144 ASN1_OBJECT *obj = X509_NAME_ENTRY_get_object(ne);
145 int nid = OBJ_obj2nid(obj);
146 const char *str = OBJ_nid2sn(nid);
147 if (str == NULL) {
148 LOGE("OBJ_nid2sn error!");
149 CfFree(neArr);
150 neArr = NULL;
151 return CF_ERR_CRYPTO_OPERATION;
152 }
153
154 if (strlen(str) == (unsigned int)(type->size - 1) && memcmp(str, type->data, strlen(str)) == 0) {
155 neArr[j++] = ne;
156 }
157 }
158
159 if (j > 0) {
160 CfResult res = GetDataByEntryOpenssl(j, outArr, neArr);
161 CfFree(neArr);
162 neArr = NULL;
163 return res;
164 }
165
166 CfFree(neArr);
167 neArr = NULL;
168 return CF_SUCCESS;
169 }
170
GetNameOpenssl(HcfX509DistinguishedNameSpi * self,CfBlob * type,CfBlob * out,CfArray * outArr)171 static CfResult GetNameOpenssl(HcfX509DistinguishedNameSpi *self, CfBlob *type, CfBlob *out, CfArray *outArr)
172 {
173 if (self == NULL) {
174 LOGE("The input data is null!");
175 return CF_INVALID_PARAMS;
176 }
177 if (!CfIsClassMatch((CfObjectBase *)self, GetX509DistinguishedNameClass())) {
178 LOGE("Input wrong class type!");
179 return CF_INVALID_PARAMS;
180 }
181 HcfX509DistinguishedNameOpensslImpl *realName = (HcfX509DistinguishedNameOpensslImpl *)self;
182 if (out != NULL) {
183 char *oneline = X509_NAME_oneline(realName->name, NULL, 0);
184 if (oneline == NULL) {
185 LOGE("X509_NAME_oneline error");
186 return CF_ERR_CRYPTO_OPERATION;
187 }
188 CfResult res = DeepCopyDataToOut(oneline, strlen(oneline), out);
189 OPENSSL_free(oneline);
190 return res;
191 }
192 return GetNameTypeByOpenssl(realName, type, outArr);
193 }
194
GetNameExOpenssl(HcfX509DistinguishedNameSpi * self,CfEncodinigType encodingType,CfBlob * out)195 static CfResult GetNameExOpenssl(HcfX509DistinguishedNameSpi *self, CfEncodinigType encodingType, CfBlob *out)
196 {
197 if ((self == NULL) || (out == NULL)) {
198 LOGE("The input data is null!");
199 return CF_ERR_INTERNAL;
200 }
201 if (encodingType != CF_ENCODING_UTF8) {
202 LOGE("encodingType is not utf8!");
203 return CF_ERR_PARAMETER_CHECK;
204 }
205 if (!CfIsClassMatch((CfObjectBase *)self, GetX509DistinguishedNameClass())) {
206 LOGE("Input wrong class type!");
207 return CF_ERR_INTERNAL;
208 }
209 HcfX509DistinguishedNameOpensslImpl *realName = (HcfX509DistinguishedNameOpensslImpl *)self;
210 BIO *bio = BIO_new(BIO_s_mem());
211 if (bio == NULL) {
212 LOGE("BIO new fail.");
213 CfPrintOpensslError();
214 return CF_ERR_MALLOC;
215 }
216 int ret = X509_NAME_print_ex(bio, realName->name, 0, XN_FLAG_SEP_COMMA_PLUS | ASN1_STRFLGS_UTF8_CONVERT);
217 if (ret <= 0) {
218 LOGE("Failed to X509_NAME_print_ex in openssl!");
219 CfPrintOpensslError();
220 BIO_free(bio);
221 return CF_ERR_CRYPTO_OPERATION;
222 }
223 CfResult res = CopyMemFromBIO(bio, out);
224 if (res != CF_SUCCESS) {
225 LOGE("CopyMemFromBIO failed!");
226 BIO_free(bio);
227 return ret;
228 }
229 BIO_free(bio);
230 return CF_SUCCESS;
231 }
232
SetValueToX509Name(X509_NAME * name,int chtype,char * typestr,unsigned char * valstr,int isMulti)233 static CfResult SetValueToX509Name(X509_NAME *name, int chtype, char *typestr, unsigned char *valstr, int isMulti)
234 {
235 int nid = OBJ_txt2nid(typestr);
236 if (nid == NID_undef) {
237 LOGW("Ignore unknown name attribute");
238 return CF_SUCCESS;
239 }
240
241 if (*valstr == '\0') {
242 LOGW("No value provided for name attribute");
243 return CF_SUCCESS;
244 }
245
246 if (!X509_NAME_add_entry_by_NID(name, nid, chtype, valstr, strlen((char *)valstr), -1, isMulti ? -1 : 0)) {
247 LOGE("Error adding name attribute");
248 return CF_INVALID_PARAMS;
249 }
250 return CF_SUCCESS;
251 }
252
CollectAndParseName(const char * cp,char * work,int chtype,X509_NAME * name)253 static CfResult CollectAndParseName(const char *cp, char *work, int chtype, X509_NAME *name)
254 {
255 int multiFlag = 0;
256 while (*cp != '\0') {
257 char *bp = work;
258 char *typestr = bp;
259 int isMulti = multiFlag;
260 multiFlag = 0;
261
262 while (*cp != '\0' && *cp != '=') {
263 *bp++ = *cp++;
264 }
265 *bp++ = '\0';
266 if (*cp == '\0') {
267 LOGE("Not has RDN type string");
268 return CF_INVALID_PARAMS;
269 }
270 cp++;
271
272 unsigned char *valstr = (unsigned char *)bp;
273 while (*cp != '\0' && *cp != '/') {
274 if (*cp == '+') {
275 multiFlag = 1;
276 break;
277 }
278 const char *t = cp;
279 t++;
280 if (*cp == '\\' && *t == '\0') {
281 LOGE("Escape character at end of name string");
282 return CF_INVALID_PARAMS;
283 }
284 if (*cp == '\\') {
285 cp++;
286 }
287 *bp++ = *cp++;
288 }
289 *bp++ = '\0';
290 if (*cp != '\0') {
291 cp++;
292 }
293
294 int ret = SetValueToX509Name(name, chtype, typestr, valstr, isMulti);
295 if (ret != CF_SUCCESS) {
296 return ret;
297 }
298 }
299 return CF_SUCCESS;
300 }
301
ParseName(const char * cp,int chtype,const char * desc)302 static X509_NAME *ParseName(const char *cp, int chtype, const char *desc)
303 {
304 if (*cp++ != '/') {
305 LOGE("name is expected to be in the format");
306 return NULL;
307 }
308
309 X509_NAME *name = X509_NAME_new();
310 if (name == NULL) {
311 LOGE("Out of memory");
312 return NULL;
313 }
314 char *work = OPENSSL_strdup(cp);
315 if (work == NULL) {
316 LOGE("Error copying name input");
317 goto err;
318 }
319
320 if (CollectAndParseName(cp, work, chtype, name) != CF_SUCCESS) {
321 LOGE("Error CollectAndParseName");
322 goto err;
323 }
324
325 OPENSSL_free(work);
326 return name;
327
328 err:
329 X509_NAME_free(name);
330 OPENSSL_free(work);
331 return NULL;
332 }
333
OpensslX509DistinguishedNameSpiCreate(const CfBlob * inStream,const bool bString,HcfX509DistinguishedNameSpi ** spi)334 CfResult OpensslX509DistinguishedNameSpiCreate(const CfBlob *inStream, const bool bString,
335 HcfX509DistinguishedNameSpi **spi)
336 {
337 if ((inStream == NULL) || inStream->data == NULL || (spi == NULL)) {
338 LOGE("The input data blob is null!");
339 return CF_INVALID_PARAMS;
340 }
341 X509_NAME *name = NULL;
342 if (bString) {
343 name = ParseName((const char *)inStream->data, MBSTRING_UTF8, "DistinguishedName");
344 } else {
345 const unsigned char *in = inStream->data;
346 name = d2i_X509_NAME(NULL, &in, inStream->size);
347 }
348
349 if (name == NULL) {
350 CfPrintOpensslError();
351 LOGE("the name is null!");
352 return CF_ERR_CRYPTO_OPERATION;
353 }
354
355 HcfX509DistinguishedNameOpensslImpl *realName = (HcfX509DistinguishedNameOpensslImpl *)CfMalloc(
356 sizeof(HcfX509DistinguishedNameOpensslImpl), 0);
357 if (realName == NULL) {
358 LOGE("CfMalloc error");
359 X509_NAME_free(name);
360 return CF_ERR_MALLOC;
361 }
362
363 realName->name = name;
364 realName->base.base.getClass = GetX509DistinguishedNameClass;
365 realName->base.base.destroy = DestroyX509DistinguishedNameOpenssl;
366 realName->base.engineGetEncode = GetEncodeOpenssl;
367 realName->base.engineGetName = GetNameOpenssl;
368 realName->base.engineGetNameEx = GetNameExOpenssl;
369 *spi = (HcfX509DistinguishedNameSpi *)realName;
370 return CF_SUCCESS;
371 }
372