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