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