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 
36 typedef struct {
37     HcfX509DistinguishedNameSpi base;
38     X509_NAME *name;
39 } HcfX509DistinguishedNameOpensslImpl;
40 
GetX509DistinguishedNameClass(void)41 static const char *GetX509DistinguishedNameClass(void)
42 {
43     return X509_DISTINGUISHED_NAME_OPENSSL_CLASS;
44 }
45 
DestroyX509DistinguishedNameOpenssl(CfObjectBase * self)46 static void DestroyX509DistinguishedNameOpenssl(CfObjectBase *self)
47 {
48     if (self == NULL) {
49         return;
50     }
51     if (!CfIsClassMatch(self, GetX509DistinguishedNameClass())) {
52         LOGE("Input wrong class type!");
53         return;
54     }
55     HcfX509DistinguishedNameOpensslImpl *realName = (HcfX509DistinguishedNameOpensslImpl *)self;
56     X509_NAME_free(realName->name);
57     realName->name = NULL;
58     CfFree(realName);
59 }
60 
GetEncodeOpenssl(HcfX509DistinguishedNameSpi * self,CfEncodingBlob * out)61 static CfResult GetEncodeOpenssl(HcfX509DistinguishedNameSpi *self, CfEncodingBlob *out)
62 {
63     if ((self == NULL) || (out == NULL)) {
64         LOGE("The input data is null!");
65         return CF_INVALID_PARAMS;
66     }
67     if (!CfIsClassMatch((CfObjectBase *)self, GetX509DistinguishedNameClass())) {
68         LOGE("Input wrong class type!");
69         return CF_INVALID_PARAMS;
70     }
71     HcfX509DistinguishedNameOpensslImpl *realName = (HcfX509DistinguishedNameOpensslImpl *)self;
72     size_t len = 0;
73     const unsigned char *p = NULL;
74     if (X509_NAME_get0_der(realName->name, &p, &len) == 1) {
75         out->data = (uint8_t *)CfMalloc((uint32_t)len, 0);
76         if (out->data == NULL) {
77             LOGE("Failed to malloc for encoded data!");
78             return CF_ERR_MALLOC;
79         }
80         if (memcpy_s(out->data, len, p, len) != EOK) {
81             LOGE("memcpy_s data to buffer failed!");
82             CfFree(out->data);
83             return CF_ERR_COPY;
84         }
85 
86         out->len = len;
87         out->encodingFormat = CF_FORMAT_DER;
88         return CF_SUCCESS;
89     }
90 
91     LOGE("X509_NAME_get0_der error!");
92     return CF_ERR_CRYPTO_OPERATION;
93 }
94 
GetDataByEntryOpenssl(int32_t count,CfArray * outArr,X509_NAME_ENTRY ** neArr)95 static CfResult GetDataByEntryOpenssl(int32_t count, CfArray *outArr, X509_NAME_ENTRY **neArr)
96 {
97     if (count <= 0 || outArr == NULL || *neArr == NULL) {
98         LOGE("GetDataByEntryOpenssl data is null!");
99         return CF_INVALID_PARAMS;
100     }
101 
102     outArr->data = (CfBlob *)CfMalloc(count * sizeof(CfBlob), 0);
103     if (outArr->data == NULL) {
104         LOGE("CfMalloc error");
105         return CF_ERR_MALLOC;
106     }
107     outArr->count = count;
108     for (int i = 0; i < count; ++i) {
109         ASN1_STRING *str = X509_NAME_ENTRY_get_data(neArr[i]);
110         unsigned char *p = ASN1_STRING_data(str);
111         int len = ASN1_STRING_length(str);
112         if (len <= 0) {
113             LOGE("ASN1_STRING_length error");
114             CfArrayDataClearAndFree(outArr);
115             return CF_ERR_CRYPTO_OPERATION;
116         }
117         CfResult res = DeepCopyDataToOut((const char *)p, len, &(outArr->data[i]));
118         if (res != CF_SUCCESS) {
119             LOGE("DeepCopyDataToOut error");
120             CfArrayDataClearAndFree(outArr);
121             return res;
122         }
123     }
124     return CF_SUCCESS;
125 }
126 
GetNameTypeByOpenssl(HcfX509DistinguishedNameOpensslImpl * realName,CfBlob * type,CfArray * outArr)127 static CfResult GetNameTypeByOpenssl(HcfX509DistinguishedNameOpensslImpl *realName, CfBlob *type, CfArray *outArr)
128 {
129     if (realName == NULL || type == NULL || outArr == NULL) {
130         LOGE("The input data is null!");
131         return CF_INVALID_PARAMS;
132     }
133 
134     if (type->size < 1) {
135         LOGE("The input type size is zero!");
136         return CF_INVALID_PARAMS;
137     }
138     X509_NAME_ENTRY **neArr = (X509_NAME_ENTRY **)CfMalloc(
139         X509_NAME_entry_count(realName->name) * sizeof(X509_NAME_ENTRY *), 0);
140     if (neArr == NULL) {
141         LOGE("CfMalloc error");
142         return CF_ERR_MALLOC;
143     }
144 
145     int j = 0;
146     for (int i = 0; i < X509_NAME_entry_count(realName->name); ++i) {
147         X509_NAME_ENTRY *ne = X509_NAME_get_entry(realName->name, i);
148         ASN1_OBJECT *obj = X509_NAME_ENTRY_get_object(ne);
149         int nid = OBJ_obj2nid(obj);
150         const char *str = OBJ_nid2sn(nid);
151         if (str == NULL) {
152             LOGE("OBJ_nid2sn error!");
153             CfFree(neArr);
154             return CF_ERR_CRYPTO_OPERATION;
155         }
156 
157         if (strlen(str) == (unsigned int)(type->size - 1) && memcmp(str, type->data, strlen(str)) == 0) {
158             neArr[j++] = ne;
159         }
160     }
161 
162     if (j > 0) {
163         CfResult res = GetDataByEntryOpenssl(j, outArr, neArr);
164         CfFree(neArr);
165         return res;
166     }
167 
168     CfFree(neArr);
169     return CF_SUCCESS;
170 }
171 
GetNameOpenssl(HcfX509DistinguishedNameSpi * self,CfBlob * type,CfBlob * out,CfArray * outArr)172 static CfResult GetNameOpenssl(HcfX509DistinguishedNameSpi *self, CfBlob *type, CfBlob *out, CfArray *outArr)
173 {
174     if (self == NULL) {
175         LOGE("The input data is null!");
176         return CF_INVALID_PARAMS;
177     }
178     if (!CfIsClassMatch((CfObjectBase *)self, GetX509DistinguishedNameClass())) {
179         LOGE("Input wrong class type!");
180         return CF_INVALID_PARAMS;
181     }
182     HcfX509DistinguishedNameOpensslImpl *realName = (HcfX509DistinguishedNameOpensslImpl *)self;
183     if (out != NULL) {
184         char *oneline = X509_NAME_oneline(realName->name, NULL, 0);
185         if (oneline == NULL) {
186             LOGE("X509_NAME_oneline error");
187             return CF_ERR_CRYPTO_OPERATION;
188         }
189         CfResult res = DeepCopyDataToOut(oneline, strlen(oneline), out);
190         OPENSSL_free(oneline);
191         return res;
192     }
193     return GetNameTypeByOpenssl(realName, type, outArr);
194 }
195 
SetValueToX509Name(X509_NAME * name,int chtype,char * typestr,unsigned char * valstr,int isMulti)196 static CfResult SetValueToX509Name(X509_NAME *name, int chtype, char *typestr, unsigned char *valstr, int isMulti)
197 {
198     int nid = OBJ_txt2nid(typestr);
199     if (nid == NID_undef) {
200         LOGW("Ignore unknown name attribute");
201         return CF_SUCCESS;
202     }
203 
204     if (*valstr == '\0') {
205         LOGW("No value provided for name attribute");
206         return CF_SUCCESS;
207     }
208 
209     if (!X509_NAME_add_entry_by_NID(name, nid, chtype, valstr, strlen((char *)valstr), -1, isMulti ? -1 : 0)) {
210         LOGE("Error adding name attribute");
211         return CF_INVALID_PARAMS;
212     }
213     return CF_SUCCESS;
214 }
215 
CollectAndParseName(const char * cp,char * work,int chtype,X509_NAME * name)216 static CfResult CollectAndParseName(const char *cp, char *work, int chtype, X509_NAME *name)
217 {
218     int multiFlag = 0;
219     while (*cp != '\0') {
220         char *bp = work;
221         char *typestr = bp;
222         int isMulti = multiFlag;
223         multiFlag = 0;
224 
225         while (*cp != '\0' && *cp != '=') {
226             *bp++ = *cp++;
227         }
228         *bp++ = '\0';
229         if (*cp == '\0') {
230             LOGE("Not has RDN type string");
231             return CF_INVALID_PARAMS;
232         }
233         cp++;
234 
235         unsigned char *valstr = (unsigned char *)bp;
236         while (*cp != '\0' && *cp != '/') {
237             if (*cp == '+') {
238                 multiFlag = 1;
239                 break;
240             }
241             const char *t = cp;
242             t++;
243             if (*cp == '\\' && *t == '\0') {
244                 LOGE("Escape character at end of name string");
245                 return CF_INVALID_PARAMS;
246             }
247             if (*cp == '\\') {
248                 cp++;
249             }
250             *bp++ = *cp++;
251         }
252         *bp++ = '\0';
253         if (*cp != '\0') {
254             cp++;
255         }
256 
257         int ret = SetValueToX509Name(name, chtype, typestr, valstr, isMulti);
258         if (ret != CF_SUCCESS) {
259             return ret;
260         }
261     }
262     return CF_SUCCESS;
263 }
264 
ParseName(const char * cp,int chtype,const char * desc)265 static X509_NAME *ParseName(const char *cp, int chtype, const char *desc)
266 {
267     if (*cp++ != '/') {
268         LOGE("name is expected to be in the format");
269         return NULL;
270     }
271 
272     X509_NAME *name = X509_NAME_new();
273     if (name == NULL) {
274         LOGE("Out of memory");
275         return NULL;
276     }
277     char *work = OPENSSL_strdup(cp);
278     if (work == NULL) {
279         LOGE("Error copying name input");
280         goto err;
281     }
282 
283     if (CollectAndParseName(cp, work, chtype, name) != CF_SUCCESS) {
284         LOGE("Error CollectAndParseName");
285         goto err;
286     }
287 
288     OPENSSL_free(work);
289     return name;
290 
291  err:
292     X509_NAME_free(name);
293     OPENSSL_free(work);
294     return NULL;
295 }
296 
OpensslX509DistinguishedNameSpiCreate(const CfBlob * inStream,const bool bString,HcfX509DistinguishedNameSpi ** spi)297 CfResult OpensslX509DistinguishedNameSpiCreate(const CfBlob *inStream, const bool bString,
298                                                HcfX509DistinguishedNameSpi **spi)
299 {
300     if ((inStream == NULL) || inStream->data == NULL || (spi == NULL)) {
301         LOGE("The input data blob is null!");
302         return CF_INVALID_PARAMS;
303     }
304     X509_NAME *name = NULL;
305     if (bString) {
306         name = ParseName((const char *)inStream->data, MBSTRING_UTF8, "DistinguishedName");
307     } else {
308         const unsigned char *in = inStream->data;
309         name = d2i_X509_NAME(NULL, &in, inStream->size);
310     }
311 
312     if (name == NULL) {
313         LOGE("the name is null!");
314         return CF_ERR_CRYPTO_OPERATION;
315     }
316 
317     HcfX509DistinguishedNameOpensslImpl *realName = (HcfX509DistinguishedNameOpensslImpl *)CfMalloc(
318         sizeof(HcfX509DistinguishedNameOpensslImpl), 0);
319     if (realName == NULL) {
320         LOGE("CfMalloc error");
321         X509_NAME_free(name);
322         return CF_ERR_MALLOC;
323     }
324 
325     realName->name = name;
326     realName->base.base.getClass = GetX509DistinguishedNameClass;
327     realName->base.base.destroy = DestroyX509DistinguishedNameOpenssl;
328     realName->base.engineGetEncode = GetEncodeOpenssl;
329     realName->base.engineGetName = GetNameOpenssl;
330     *spi = (HcfX509DistinguishedNameSpi *)realName;
331     return CF_SUCCESS;
332 }
333