1 /*
2  * Copyright (c) 2023 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 "cf_adapter_extension_openssl.h"
17 
18 #include <openssl/asn1.h>
19 #include <openssl/bio.h>
20 #include <openssl/err.h>
21 #include <openssl/evp.h>
22 #include <openssl/pem.h>
23 #include <openssl/x509v3.h>
24 
25 #include "securec.h"
26 
27 #include "cf_check.h"
28 #include "cf_log.h"
29 #include "cf_magic.h"
30 #include "cf_memory.h"
31 #include "cf_result.h"
32 
33 #define KEYUSAGE_SHIFT 8
34 #define CRITICAL_SIZE  1
35 
36 typedef struct {
37     char *oid;
38     char *extensionName;
39 } OidToExtensionName;
40 
41 static const OidToExtensionName OID_TO_EXT_NAME_MAP[] = {
42     { "2.5.29.9", "SubjectDirectoryAttributes" },
43     { "2.5.29.14", "SubjectKeyIdentifier" },
44     { "2.5.29.15", "KeyUsage" },
45     { "2.5.29.16", "PrivateKeyUsage" },
46     { "2.5.29.17", "SubjectAlternativeName" },
47     { "2.5.29.18", "IssuerAlternativeName" },
48     { "2.5.29.19", "BasicConstraints" },
49     { "2.5.29.20", "CRLNumber" },
50     { "2.5.29.21", "CRLReason" },
51     { "2.5.29.23", "HoldInstructionCode" },
52     { "2.5.29.24", "InvalidityDate" },
53     { "2.5.29.27", "DeltaCRLIndicator" },
54     { "2.5.29.28", "IssuingDistributionPoint" },
55     { "2.5.29.29", "CertificateIssuer" },
56     { "2.5.29.30", "NameConstraints" },
57     { "2.5.29.31", "CRLDistributionPoints" },
58     { "2.5.29.32", "CertificatePolicies" },
59     { "2.5.29.33", "PolicyMappings" },
60     { "2.5.29.35", "AuthorityKeyIdentifier" },
61     { "2.5.29.36", "PolicyConstraints" },
62     { "2.5.29.37", "ExtendedKeyUsage" },
63     { "2.5.29.46", "FreshestCRL" },
64     { "2.5.29.54", "InhibitAnyPolicy" },
65     { "1.3.6.1.5.5.7.1.1", "AuthInfoAccess" },
66     { "1.3.6.1.5.5.7.1.11", "SubjectInfoAccess" },
67     { "1.3.6.1.5.5.7.48.1.5", "OCSPNoCheck" },
68     { "2.16.840.1.113730.1.1", "NETSCAPECert" }
69 };
70 
CfOpensslCreateExtension(const CfEncodingBlob * inData,CfBase ** object)71 int32_t CfOpensslCreateExtension(const CfEncodingBlob *inData, CfBase **object)
72 {
73     if ((CfCheckEncodingBlob(inData, MAX_LEN_EXTENSIONS) != CF_SUCCESS) ||
74         (inData->encodingFormat != CF_FORMAT_DER) || (object == NULL)) {
75         CF_LOG_E("invalid input params");
76         return CF_INVALID_PARAMS;
77     }
78 
79     CfOpensslExtensionObj *extsObj = CfMalloc(sizeof(CfOpensslExtensionObj), 0);
80     if (extsObj == NULL) {
81         CF_LOG_E("malloc failed");
82         return CF_ERR_MALLOC;
83     }
84     extsObj->base.type = CF_MAGIC(CF_MAGIC_TYPE_ADAPTER_RESOURCE, CF_OBJ_TYPE_EXTENSION);
85 
86     uint8_t *end = inData->data; /* data pointer will shift downward in d2i_X509_EXTENSIONS */
87     extsObj->exts = d2i_X509_EXTENSIONS(NULL, (const unsigned char **)&end, inData->len);
88     if (extsObj->exts == NULL) {
89         CF_LOG_E("Failed to get internal extension");
90         CfFree(extsObj);
91         return CF_ERR_CRYPTO_OPERATION;
92     }
93 
94     if (end != (inData->data + inData->len)) { /* Tainted extension data: valid part + invalid part */
95         CF_LOG_E("The extension indata is invalid");
96         sk_X509_EXTENSION_pop_free(extsObj->exts, X509_EXTENSION_free);
97         CfFree(extsObj);
98         return CF_ERR_CRYPTO_OPERATION;
99     }
100 
101     *object = &extsObj->base;
102     return CF_SUCCESS;
103 }
104 
CfOpensslDestoryExtension(CfBase ** object)105 void CfOpensslDestoryExtension(CfBase **object)
106 {
107     if ((object == NULL) || (*object == NULL)) {
108         CF_LOG_E("invalid input params");
109         return;
110     }
111 
112     CfOpensslExtensionObj *extsObj = (CfOpensslExtensionObj *)*object;
113     if (extsObj->base.type != CF_MAGIC(CF_MAGIC_TYPE_ADAPTER_RESOURCE, CF_OBJ_TYPE_EXTENSION)) {
114         CF_LOG_E("the object is invalid , type = %lu", extsObj->base.type);
115         return;
116     }
117 
118     if (extsObj->exts != NULL) {
119         sk_X509_EXTENSION_pop_free(extsObj->exts, X509_EXTENSION_free);
120     }
121     CfFree(extsObj);
122     *object = NULL;
123     return;
124 }
125 
CheckObjectAndGetExts(const CfBase * object,X509_EXTENSIONS ** exts)126 static int32_t CheckObjectAndGetExts(const CfBase *object, X509_EXTENSIONS **exts)
127 {
128     CfOpensslExtensionObj *extsObj = (CfOpensslExtensionObj *)object;
129     if (extsObj->base.type != CF_MAGIC(CF_MAGIC_TYPE_ADAPTER_RESOURCE, CF_OBJ_TYPE_EXTENSION)) {
130         CF_LOG_E("the object is invalid , type = %lu", extsObj->base.type);
131         return CF_INVALID_PARAMS;
132     }
133 
134     if (extsObj->exts == NULL) {
135         CF_LOG_E("extension is null");
136         return CF_INVALID_PARAMS;
137     }
138 
139     *exts = extsObj->exts;
140     return CF_SUCCESS;
141 }
142 
CopyIndexArray(uint32_t * destArray,uint32_t * destLen,const uint32_t * srcArray,uint32_t srcLen)143 static int32_t CopyIndexArray(uint32_t *destArray, uint32_t *destLen, const uint32_t *srcArray, uint32_t srcLen)
144 {
145     if (memcpy_s(destArray, ((*destLen) * sizeof(uint32_t)), srcArray, (srcLen * sizeof(uint32_t))) != EOK) {
146         CF_LOG_E("Failed to copy index array");
147         return CF_ERR_COPY;
148     }
149     *destLen = srcLen;
150     return CF_SUCCESS;
151 }
152 
GetExtensionIndexArray(const X509_EXTENSIONS * exts,CfExtensionOidType type,uint32_t * array,uint32_t * arrayLen)153 static int32_t GetExtensionIndexArray(const X509_EXTENSIONS *exts, CfExtensionOidType type,
154     uint32_t *array, uint32_t *arrayLen)
155 {
156     int32_t extNums = sk_X509_EXTENSION_num(exts);
157     if ((extNums <= 0) || (extNums > MAX_COUNT_OID)) {
158         CF_LOG_E("Failed to get extension numbers");
159         return CF_ERR_CRYPTO_OPERATION;
160     }
161 
162     uint32_t allOidArray[MAX_COUNT_OID] = { 0 }; /* type: CF_EXT_TYPE_ALL_OIDS */
163     uint32_t critOidArray[MAX_COUNT_OID] = { 0 }; /* type: CF_EXT_TYPE_CRITICAL_OIDS */
164     uint32_t uncritOidArray[MAX_COUNT_OID] = { 0 }; /* type: CF_EXT_TYPE_UNCRITICAL_OIDS */
165     uint32_t critCnt = 0;
166     uint32_t uncritCnt = 0;
167 
168     for (uint32_t i = 0; i < (uint32_t)extNums; ++i) {
169         allOidArray[i] = i;
170 
171         X509_EXTENSION *ex = sk_X509_EXTENSION_value(exts, i);
172         if (ex == NULL) {
173             CF_LOG_E("Failed to get exts [%u] value", i);
174             return CF_ERR_CRYPTO_OPERATION;
175         }
176 
177         int crit = X509_EXTENSION_get_critical(ex);
178         if (crit == 1) {
179             critOidArray[critCnt++] = i;
180         } else {
181             uncritOidArray[uncritCnt++] = i;
182         }
183     }
184 
185     switch (type) {
186         case CF_EXT_TYPE_ALL_OIDS:
187             return CopyIndexArray(array, arrayLen, allOidArray, (uint32_t)extNums);
188         case CF_EXT_TYPE_CRITICAL_OIDS:
189             return CopyIndexArray(array, arrayLen, critOidArray, critCnt);
190         case CF_EXT_TYPE_UNCRITICAL_OIDS:
191             return CopyIndexArray(array, arrayLen, uncritOidArray, uncritCnt);
192         default:
193             CF_LOG_E("type is invalid");
194             return CF_INVALID_PARAMS;
195     }
196 }
197 
DeepCopyDataToOutblob(const char * data,uint32_t len,CfBlob * outBlob)198 static int32_t DeepCopyDataToOutblob(const char *data, uint32_t len, CfBlob *outBlob)
199 {
200     outBlob->data = (uint8_t *)CfMalloc(len, 0);
201     if (outBlob->data == NULL) {
202         CF_LOG_E("Failed to malloc");
203         return CF_ERR_MALLOC;
204     }
205     (void)memcpy_s(outBlob->data, len, data, len);
206     outBlob->size = len;
207     return CF_SUCCESS;
208 }
209 
DeepCopyOidsToOut(const X509_EXTENSIONS * exts,const uint32_t * idxArray,uint32_t arrayLen,CfBlobArray * out)210 static int32_t DeepCopyOidsToOut(const X509_EXTENSIONS *exts, const uint32_t *idxArray, uint32_t arrayLen,
211     CfBlobArray *out)
212 {
213     uint32_t memSize = sizeof(CfBlob) * arrayLen;
214     CfBlob *dataArray = (CfBlob *)CfMalloc(memSize, 0);
215     if (dataArray == NULL) {
216         CF_LOG_E("Failed to malloc");
217         return CF_ERR_MALLOC;
218     }
219 
220     for (uint32_t i = 0; i < arrayLen; ++i) {
221         uint32_t index = idxArray[i];
222 
223         X509_EXTENSION *ex = sk_X509_EXTENSION_value(exts, index);
224         if (ex == NULL) {
225             CF_LOG_E("Failed to get exts [%u] value", index);
226             FreeCfBlobArray(dataArray, i);
227             return CF_ERR_CRYPTO_OPERATION;
228         }
229 
230         char oid[MAX_LEN_OID] = { 0 };
231         int32_t oidLen = OBJ_obj2txt(oid, MAX_LEN_OID, X509_EXTENSION_get_object(ex), 1);
232         if ((oidLen <= 0) || (oidLen >= MAX_LEN_OID)) {
233             CF_LOG_E("Failed to get oid[%u]", index);
234             FreeCfBlobArray(dataArray, i);
235             return CF_ERR_CRYPTO_OPERATION;
236         }
237 
238         int32_t ret = DeepCopyDataToOutblob(oid, strlen(oid), &dataArray[i]);
239         if (ret != CF_SUCCESS) {
240             CF_LOG_E("Failed to copy oid[%u]", index);
241             FreeCfBlobArray(dataArray, i);
242             return ret;
243         }
244     }
245 
246     out->data = dataArray;
247     out->count = arrayLen;
248     return CF_SUCCESS;
249 }
250 
CfOpensslGetOids(const CfBase * object,CfExtensionOidType type,CfBlobArray * out)251 int32_t CfOpensslGetOids(const CfBase *object, CfExtensionOidType type, CfBlobArray *out)
252 {
253     if ((object == NULL) || (out == NULL)) {
254         CF_LOG_E("invalid input params");
255         return CF_INVALID_PARAMS;
256     }
257 
258     X509_EXTENSIONS *exts = NULL;
259     int32_t ret = CheckObjectAndGetExts(object, &exts);
260     if (ret != CF_SUCCESS) {
261         CF_LOG_E("Failed to get extension");
262         return ret;
263     }
264 
265     uint32_t idxArray[MAX_COUNT_OID] = { 0 }; /* extension index array for target CfExtensionOidType */
266     uint32_t count = MAX_COUNT_OID;
267     ret = GetExtensionIndexArray(exts, type, idxArray, &count);
268     if (ret != CF_SUCCESS) {
269         CF_LOG_E("Failed to get extension index array");
270         return ret;
271     }
272 
273     ret = DeepCopyOidsToOut(exts, idxArray, count, out);
274     if (ret != CF_SUCCESS) {
275         CF_LOG_E("Failed to copy oids to out");
276         return ret;
277     }
278     return CF_SUCCESS;
279 }
280 
CfOpensslHasUnsupportedCriticalExtension(const CfBase * object,bool * out)281 int32_t CfOpensslHasUnsupportedCriticalExtension(const CfBase *object, bool *out)
282 {
283     if (object == NULL || out == NULL) {
284         CF_LOG_E("invalid input params");
285         return CF_INVALID_PARAMS;
286     }
287 
288     X509_EXTENSIONS *exts = NULL;
289     int32_t ret = CheckObjectAndGetExts(object, &exts);
290     if (ret != CF_SUCCESS) {
291         CF_LOG_E("Failed to get extension");
292         return ret;
293     }
294 
295     int32_t extNums = sk_X509_EXTENSION_num(exts);
296     if ((extNums <= 0) || (extNums > MAX_COUNT_OID)) {
297         CF_LOG_E("Failed to get extension numbers, extNums = %d", extNums);
298         return CF_ERR_CRYPTO_OPERATION;
299     }
300 
301     for (uint32_t i = 0; i < (uint32_t)extNums; ++i) {
302         X509_EXTENSION *ex = sk_X509_EXTENSION_value(exts, i);
303         if (ex == NULL) {
304             CF_LOG_E("Failed to get exts [%u] value", i);
305             return CF_ERR_CRYPTO_OPERATION;
306         }
307 
308         int crit = X509_EXTENSION_get_critical(ex);
309         if (crit != 1) { /* the extension entry is critical */
310             continue;
311         }
312 
313         char oid[MAX_LEN_OID] = { 0 };
314         int32_t oidLen = OBJ_obj2txt(oid, MAX_LEN_OID, X509_EXTENSION_get_object(ex), 1);
315         if ((oidLen <= 0) || (oidLen >= MAX_LEN_OID)) {
316             CF_LOG_E("Failed to get ext oid");
317             return CF_ERR_CRYPTO_OPERATION;
318         }
319         uint32_t oidsCount = sizeof(OID_TO_EXT_NAME_MAP) / sizeof(OidToExtensionName);
320         bool match = false;
321         for (uint32_t oidInd = 0; oidInd < oidsCount; oidInd++) {
322             if (strcmp(OID_TO_EXT_NAME_MAP[oidInd].oid, oid) == 0) {
323                 match = true;
324                 break;
325             }
326         }
327         if (!match) {
328             CF_LOG_I("extension oid [%s] is not supported.", oid);
329             *out = true;
330             return CF_SUCCESS;
331         }
332     }
333     *out = false;
334     return CF_SUCCESS;
335 }
336 
GetTargetNid(const CfBlob * oid,int * nid)337 static int GetTargetNid(const CfBlob *oid, int *nid)
338 {
339     uint32_t length = oid->size + 1; /* add '\0' in the end */
340     uint8_t *oidString = (uint8_t *)CfMalloc(length, 0);
341     if (oidString == NULL) {
342         CF_LOG_E("Failed to malloc oid string");
343         return CF_ERR_MALLOC;
344     }
345 
346     if (memcpy_s(oidString, length, oid->data, oid->size) != EOK) {
347         CF_LOG_E("Failed to copy oid string");
348         CfFree(oidString);
349         return CF_ERR_COPY;
350     }
351 
352     *nid = OBJ_txt2nid((char *)oidString);
353     CfFree(oidString);
354     return CF_SUCCESS;
355 }
356 
FoundExtMatchedNid(const X509_EXTENSIONS * exts,int targetNid,X509_EXTENSION ** found)357 static int32_t FoundExtMatchedNid(const X509_EXTENSIONS *exts, int targetNid, X509_EXTENSION **found)
358 {
359     int32_t extNums = sk_X509_EXTENSION_num(exts);
360     if ((extNums <= 0) || (extNums > MAX_COUNT_OID)) {
361         CF_LOG_E("Failed to get extension numbers");
362         return CF_ERR_CRYPTO_OPERATION;
363     }
364 
365     for (int i = 0; i < extNums; ++i) {
366         X509_EXTENSION *ex = sk_X509_EXTENSION_value(exts, i);
367         if (ex == NULL) {
368             CF_LOG_E("Failed to get exts [%d] value", i);
369             return CF_ERR_CRYPTO_OPERATION;
370         }
371 
372         int nid = OBJ_obj2nid(X509_EXTENSION_get_object(ex));
373         if (nid == NID_undef) {
374             CF_LOG_E("nid undefined");
375             return CF_ERR_CRYPTO_OPERATION;
376         }
377 
378         if (targetNid == nid) {
379             *found = ex;
380             return CF_SUCCESS;
381         }
382     }
383     return CF_NOT_EXIST;
384 }
385 
GetEntry(const X509_EXTENSION * found,CfBlob * out)386 static int32_t GetEntry(const X509_EXTENSION *found, CfBlob *out)
387 {
388     unsigned char *entry = NULL;
389     int entryLen = i2d_X509_EXTENSION((X509_EXTENSION *)found, &entry);
390     if (entryLen <= 0) {
391         CF_LOG_E("Failed to get entry");
392         return CF_ERR_CRYPTO_OPERATION;
393     }
394 
395     int32_t ret = DeepCopyDataToOutblob((const char *)entry, entryLen, out);
396     OPENSSL_free(entry);
397     return ret;
398 }
399 
GetEntryCritical(const X509_EXTENSION * found,CfBlob * out)400 static int32_t GetEntryCritical(const X509_EXTENSION *found, CfBlob *out)
401 {
402     out->data = (uint8_t *)CfMalloc(CRITICAL_SIZE, 0); /* critical value is 0 or 1 */
403     if (out->data == NULL) {
404         CF_LOG_E("Failed to malloc");
405         return CF_ERR_MALLOC;
406     }
407     out->size = CRITICAL_SIZE;
408 
409     int crit = X509_EXTENSION_get_critical(found);
410     if (crit == 1) {
411         out->data[0] = 1;
412     } else {
413         out->data[0] = 0;
414     }
415 
416     return CF_SUCCESS;
417 }
418 
GetEntryValue(const X509_EXTENSION * found,CfBlob * out)419 static int32_t GetEntryValue(const X509_EXTENSION *found, CfBlob *out)
420 {
421     /* return internal value: extension data */
422     ASN1_OCTET_STRING *octetString = X509_EXTENSION_get_data((X509_EXTENSION *)found);
423     if (octetString == NULL) {
424         CF_LOG_E("Failed to get entry value");
425         return CF_ERR_CRYPTO_OPERATION;
426     }
427 
428     unsigned char *entryValue = NULL;
429     int entryValueLen = i2d_ASN1_OCTET_STRING(octetString, &entryValue);
430     if (entryValueLen <= 0) {
431         CF_LOG_E("Failed to get entry value len");
432         return CF_ERR_CRYPTO_OPERATION;
433     }
434 
435     int32_t ret = DeepCopyDataToOutblob((char *)entryValue, entryValueLen, out);
436     OPENSSL_free(entryValue);
437     return ret;
438 }
439 
GetMatchedEntry(const X509_EXTENSION * found,CfExtensionEntryType type,CfBlob * out)440 static int32_t GetMatchedEntry(const X509_EXTENSION *found, CfExtensionEntryType type, CfBlob *out)
441 {
442     switch (type) {
443         case CF_EXT_ENTRY_TYPE_ENTRY:
444             return GetEntry(found, out);
445         case CF_EXT_ENTRY_TYPE_ENTRY_CRITICAL:
446             return GetEntryCritical(found, out);
447         case CF_EXT_ENTRY_TYPE_ENTRY_VALUE:
448             return GetEntryValue(found, out);
449         default:
450             CF_LOG_E("type id invalid");
451             return CF_INVALID_PARAMS;
452     }
453 }
454 
CfOpensslGetEntry(const CfBase * object,CfExtensionEntryType type,const CfBlob * oid,CfBlob * out)455 int32_t CfOpensslGetEntry(const CfBase *object, CfExtensionEntryType type, const CfBlob *oid, CfBlob *out)
456 {
457     if ((object == NULL) || (out == NULL) || (CfCheckBlob(oid, MAX_LEN_OID) != CF_SUCCESS)) {
458         CF_LOG_E("invalid input params");
459         return CF_INVALID_PARAMS;
460     }
461 
462     X509_EXTENSIONS *exts = NULL;
463     int32_t ret = CheckObjectAndGetExts(object, &exts);
464     if (ret != CF_SUCCESS) {
465         CF_LOG_E("Failed to get extension");
466         return ret;
467     }
468 
469     /* get target nid from oid */
470     int targetNid;
471     ret = GetTargetNid(oid, &targetNid);
472     if ((ret != CF_SUCCESS) || (targetNid == NID_undef)) {
473         CF_LOG_E("nid is undefined");
474         ret = (ret == CF_SUCCESS) ? CF_INVALID_PARAMS : ret;
475         return ret;
476     }
477 
478     /* found one extension matched target nid in extensions */
479     X509_EXTENSION *found = NULL;
480     ret = FoundExtMatchedNid(exts, targetNid, &found);
481     if (ret != CF_SUCCESS) {
482         CF_LOG_E("no found target nid");
483         return ret;
484     }
485 
486     /* get entry from matched extension for target type */
487     ret = GetMatchedEntry(found, type, out);
488     if (ret != CF_SUCCESS) {
489         CF_LOG_E("Failed to get matched entry");
490         return ret;
491     }
492     return CF_SUCCESS;
493 }
494 
CheckKeyUsage(const X509_EXTENSIONS * exts,int32_t * pathLen)495 static int32_t CheckKeyUsage(const X509_EXTENSIONS *exts, int32_t *pathLen)
496 {
497     ASN1_BIT_STRING *usage = (ASN1_BIT_STRING *)X509V3_get_d2i(exts, NID_key_usage, NULL, NULL);
498     if (usage == NULL) {
499         CF_LOG_E("Failed to get usage");
500         return CF_ERR_CRYPTO_OPERATION;
501     }
502 
503     uint32_t keyUsage = (uint32_t)usage->data[0];
504     if (usage->length > 1) {
505         keyUsage |= ((uint32_t)usage->data[1] << KEYUSAGE_SHIFT);
506     }
507 
508     /* keyUsage of a CA cert: sign */
509     if ((keyUsage & KU_KEY_CERT_SIGN) == 0) {
510         CF_LOG_I("this cert not a CA");
511         *pathLen = BASIC_CONSTRAINTS_NO_CA;
512     }
513 
514     ASN1_BIT_STRING_free(usage);
515     return CF_SUCCESS;
516 }
517 
CheckBasicConstraints(const X509_EXTENSIONS * exts,int32_t * pathLen)518 static int32_t CheckBasicConstraints(const X509_EXTENSIONS *exts, int32_t *pathLen)
519 {
520     BASIC_CONSTRAINTS *bs = (BASIC_CONSTRAINTS *)X509V3_get_d2i(exts, NID_basic_constraints, NULL, NULL);
521     if (bs == NULL) {
522         CF_LOG_E("Failed to get basic constraints");
523         return CF_ERR_CRYPTO_OPERATION;
524     }
525 
526     int32_t ret = CF_SUCCESS;
527     do {
528         if (!bs->ca) {
529             CF_LOG_I("this cert not a CA");
530             /* CheckCA operation is success, but cert is not a CA, pathLen set -1 */
531             *pathLen = BASIC_CONSTRAINTS_NO_CA;
532             ret = CF_SUCCESS;
533             break;
534         }
535 
536         if ((bs->pathlen == NULL) || (bs->pathlen->type == V_ASN1_NEG_INTEGER)) {
537             CF_LOG_I("this cert pathlen no limit");
538             /* CheckCA operation is success and cert is a CA, but no limit to pathlen, pathLen set -2 */
539             *pathLen = BASIC_CONSTRAINTS_PATHLEN_NO_LIMIT;
540             ret = CF_SUCCESS;
541             break;
542         }
543 
544         long len = ASN1_INTEGER_get(bs->pathlen);
545         if ((len < 0) || (len > INT_MAX)) { /* CheckCA operation is exceptional, pathlen is invalid */
546             CF_LOG_E("this cert pathlen is invalid");
547             ret = CF_ERR_CRYPTO_OPERATION;
548             break;
549         }
550         *pathLen = (int32_t)len;
551     } while (0);
552 
553     BASIC_CONSTRAINTS_free(bs);
554     return ret;
555 }
556 
CfOpensslCheckCA(const CfBase * object,int32_t * pathLen)557 int32_t CfOpensslCheckCA(const CfBase *object, int32_t *pathLen)
558 {
559     if ((object == NULL) || (pathLen == NULL)) {
560         CF_LOG_E("invalid input params");
561         return CF_INVALID_PARAMS;
562     }
563 
564     X509_EXTENSIONS *exts = NULL;
565     int32_t ret = CheckObjectAndGetExts(object, &exts);
566     if (ret != CF_SUCCESS) {
567         CF_LOG_E("Failed to get extension");
568         return ret;
569     }
570 
571     *pathLen = 0;
572     ret = CheckKeyUsage(exts, pathLen);
573     if (ret != CF_SUCCESS) {
574         CF_LOG_E("Failed to check keyUsage");
575         return ret;
576     }
577     if (*pathLen != 0) { /* checkKeyUsage operation success, but cert has no signing purpose, pathLen set -1. */
578         CF_LOG_I("Return: this cert not a CA");
579         return ret;
580     }
581 
582     ret = CheckBasicConstraints(exts, pathLen);
583     if (ret != CF_SUCCESS) {
584         CF_LOG_E("Failed to check basicConstraints");
585         return ret;
586     }
587     return ret;
588 }
589 
GetExtensionEncoded(const X509_EXTENSIONS * inExts,CfBlob * out)590 static int32_t GetExtensionEncoded(const X509_EXTENSIONS *inExts, CfBlob *out)
591 {
592     unsigned char *derExts = NULL;
593     int extsLen = i2d_X509_EXTENSIONS((X509_EXTENSIONS *)inExts, &derExts);
594     if (extsLen <= 0) {
595         CF_LOG_E("Failed to convert internal exts to der format");
596         return CF_ERR_CRYPTO_OPERATION;
597     }
598 
599     int32_t ret = DeepCopyDataToOutblob((const char *)derExts, extsLen, out);
600     OPENSSL_free(derExts);
601     return ret;
602 }
603 
CfOpensslGetExtensionItem(const CfBase * object,CfItemId id,CfBlob * out)604 int32_t CfOpensslGetExtensionItem(const CfBase *object, CfItemId id, CfBlob *out)
605 {
606     if ((out == NULL) || (object == NULL)) {
607         CF_LOG_E("invalid input params");
608         return CF_INVALID_PARAMS;
609     }
610 
611     X509_EXTENSIONS *inExts = NULL;
612     int32_t ret = CheckObjectAndGetExts(object, &inExts);
613     if (ret != CF_SUCCESS) {
614         CF_LOG_E("Failed to get extension");
615         return ret;
616     }
617 
618     switch (id) {
619         case CF_ITEM_ENCODED:
620             return GetExtensionEncoded(inExts, out);
621         default:
622             CF_LOG_E("id is invalid");
623             return CF_INVALID_PARAMS;
624     }
625 }
626