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 "x509_certificate.h"
17
18 #include <securec.h>
19
20 #include "config.h"
21 #include "fwk_class.h"
22 #include "x509_certificate_openssl.h"
23 #include "cf_log.h"
24 #include "cf_memory.h"
25 #include "utils.h"
26 #include "x509_cert_match_parameters.h"
27 #include "x509_csr_openssl.h"
28
29 typedef CfResult (*HcfX509CertificateSpiCreateFunc)(const CfEncodingBlob *, HcfX509CertificateSpi **);
30
31 typedef struct {
32 HcfX509CertificateSpiCreateFunc createFunc;
33 } HcfX509CertificateFuncSet;
34
35 typedef struct {
36 char *certType;
37 HcfX509CertificateFuncSet funcSet;
38 } HcfCCertFactoryAbility;
39
GetX509CertificateClass(void)40 static const char *GetX509CertificateClass(void)
41 {
42 return HCF_X509_CERTIFICATE_CLASS;
43 }
44
45 static const HcfCCertFactoryAbility X509_CERTIFICATE_ABILITY_SET[] = {
46 { "X509", { OpensslX509CertSpiCreate, } }
47 };
48
FindAbility(const char * certType)49 static const HcfX509CertificateFuncSet *FindAbility(const char *certType)
50 {
51 if (certType == NULL) {
52 LOGE("CertType is null!");
53 return NULL;
54 }
55 for (uint32_t i = 0; i < sizeof(X509_CERTIFICATE_ABILITY_SET) / sizeof(HcfCCertFactoryAbility); i++) {
56 if (strcmp(X509_CERTIFICATE_ABILITY_SET[i].certType, certType) == 0) {
57 return &(X509_CERTIFICATE_ABILITY_SET[i].funcSet);
58 }
59 }
60 LOGE("Cert not support! [cert]: %s", certType);
61 return NULL;
62 }
63
DestroyX509Certificate(CfObjectBase * self)64 static void DestroyX509Certificate(CfObjectBase *self)
65 {
66 if (self == NULL) {
67 LOGE("Invalid input parameter.");
68 return;
69 }
70 if (!CfIsClassMatch(self, GetX509CertificateClass())) {
71 LOGE("Class is not match.");
72 return;
73 }
74 HcfX509CertificateImpl *impl = (HcfX509CertificateImpl *)self;
75 CfObjDestroy(impl->spiObj);
76 CfFree(impl);
77 }
78
Verify(HcfCertificate * self,void * key)79 static CfResult Verify(HcfCertificate *self, void *key)
80 {
81 if ((self == NULL) || (key == NULL)) {
82 LOGE("Invalid input parameter.");
83 return CF_INVALID_PARAMS;
84 }
85 if (!CfIsClassMatch((CfObjectBase *)self, GetX509CertificateClass())) {
86 LOGE("Class is not match.");
87 return CF_INVALID_PARAMS;
88 }
89 return ((HcfX509CertificateImpl *)self)->spiObj->engineVerify(
90 ((HcfX509CertificateImpl *)self)->spiObj, (HcfPubKey *)key);
91 }
92
GetEncoded(HcfCertificate * self,CfEncodingBlob * encodedByte)93 static CfResult GetEncoded(HcfCertificate *self, CfEncodingBlob *encodedByte)
94 {
95 if ((self == NULL) || (encodedByte == NULL)) {
96 LOGE("Invalid input parameter.");
97 return CF_INVALID_PARAMS;
98 }
99 if (!CfIsClassMatch((CfObjectBase *)self, GetX509CertificateClass())) {
100 LOGE("Class is not match.");
101 return CF_INVALID_PARAMS;
102 }
103 return ((HcfX509CertificateImpl *)self)->spiObj->engineGetEncoded(
104 ((HcfX509CertificateImpl *)self)->spiObj, encodedByte);
105 }
106
GetPublicKey(HcfCertificate * self,void ** keyOut)107 static CfResult GetPublicKey(HcfCertificate *self, void **keyOut)
108 {
109 if ((self == NULL) || (keyOut == NULL)) {
110 LOGE("Invalid input parameter.");
111 return CF_INVALID_PARAMS;
112 }
113 if (!CfIsClassMatch((CfObjectBase *)self, GetX509CertificateClass())) {
114 LOGE("Class is not match.");
115 return CF_INVALID_PARAMS;
116 }
117 return ((HcfX509CertificateImpl *)self)->spiObj->engineGetPublicKey(
118 ((HcfX509CertificateImpl *)self)->spiObj, (HcfPubKey **)keyOut);
119 }
120
CheckValidityWithDate(HcfX509Certificate * self,const char * date)121 static CfResult CheckValidityWithDate(HcfX509Certificate *self, const char *date)
122 {
123 if ((self == NULL) || (date == NULL)) {
124 LOGE("Invalid input parameter.");
125 return CF_INVALID_PARAMS;
126 }
127 if (!CfIsClassMatch((CfObjectBase *)self, GetX509CertificateClass())) {
128 LOGE("Class is not match.");
129 return CF_INVALID_PARAMS;
130 }
131 return ((HcfX509CertificateImpl *)self)->spiObj->engineCheckValidityWithDate(
132 ((HcfX509CertificateImpl *)self)->spiObj, date);
133 }
134
GetVersion(HcfX509Certificate * self)135 static long GetVersion(HcfX509Certificate *self)
136 {
137 if (self == NULL) {
138 LOGE("Invalid input parameter.");
139 return INVALID_VERSION;
140 }
141 if (!CfIsClassMatch((CfObjectBase *)self, GetX509CertificateClass())) {
142 LOGE("Class is not match.");
143 return INVALID_VERSION;
144 }
145 return ((HcfX509CertificateImpl *)self)->spiObj->engineGetVersion(
146 ((HcfX509CertificateImpl *)self)->spiObj);
147 }
148
GetSerialNumber(HcfX509Certificate * self,CfBlob * out)149 static CfResult GetSerialNumber(HcfX509Certificate *self, CfBlob *out)
150 {
151 if (self == NULL) {
152 LOGE("Invalid input parameter.");
153 return CF_INVALID_PARAMS;
154 }
155 if (!CfIsClassMatch((CfObjectBase *)self, GetX509CertificateClass())) {
156 LOGE("Class is not match.");
157 return CF_INVALID_PARAMS;
158 }
159 return ((HcfX509CertificateImpl *)self)->spiObj->engineGetSerialNumber(
160 ((HcfX509CertificateImpl *)self)->spiObj, out);
161 }
162
GetIssuerName(HcfX509Certificate * self,CfBlob * out)163 static CfResult GetIssuerName(HcfX509Certificate *self, CfBlob *out)
164 {
165 if ((self == NULL) || (out == NULL)) {
166 LOGE("Invalid input parameter.");
167 return CF_INVALID_PARAMS;
168 }
169 if (!CfIsClassMatch((CfObjectBase *)self, GetX509CertificateClass())) {
170 LOGE("Class is not match.");
171 return CF_INVALID_PARAMS;
172 }
173 return ((HcfX509CertificateImpl *)self)->spiObj->engineGetIssuerName(
174 ((HcfX509CertificateImpl *)self)->spiObj, out);
175 }
176
GetSubjectName(HcfX509Certificate * self,CfBlob * out)177 static CfResult GetSubjectName(HcfX509Certificate *self, CfBlob *out)
178 {
179 if ((self == NULL) || (out == NULL)) {
180 LOGE("Invalid input parameter.");
181 return CF_INVALID_PARAMS;
182 }
183 if (!CfIsClassMatch((CfObjectBase *)self, GetX509CertificateClass())) {
184 LOGE("Class is not match.");
185 return CF_INVALID_PARAMS;
186 }
187 return ((HcfX509CertificateImpl *)self)->spiObj->engineGetSubjectName(
188 ((HcfX509CertificateImpl *)self)->spiObj, out);
189 }
190
GetSubjectNameEx(HcfX509Certificate * self,CfEncodinigType encodingType,CfBlob * out)191 static CfResult GetSubjectNameEx(HcfX509Certificate *self, CfEncodinigType encodingType, CfBlob *out)
192 {
193 if ((self == NULL) || (out == NULL) || encodingType != CF_ENCODING_UTF8) {
194 LOGE("Invalid input parameter.");
195 return CF_INVALID_PARAMS;
196 }
197 if (!CfIsClassMatch((CfObjectBase *)self, GetX509CertificateClass())) {
198 LOGE("Class is not match.");
199 return CF_INVALID_PARAMS;
200 }
201 return ((HcfX509CertificateImpl *)self)->spiObj->engineGetSubjectNameEx(
202 ((HcfX509CertificateImpl *)self)->spiObj, encodingType, out);
203 }
204
GetNotBeforeTime(HcfX509Certificate * self,CfBlob * outDate)205 static CfResult GetNotBeforeTime(HcfX509Certificate *self, CfBlob *outDate)
206 {
207 if ((self == NULL) || (outDate == NULL)) {
208 LOGE("Invalid input parameter.");
209 return CF_INVALID_PARAMS;
210 }
211 if (!CfIsClassMatch((CfObjectBase *)self, GetX509CertificateClass())) {
212 LOGE("Class is not match.");
213 return CF_INVALID_PARAMS;
214 }
215 return ((HcfX509CertificateImpl *)self)->spiObj->engineGetNotBeforeTime(
216 ((HcfX509CertificateImpl *)self)->spiObj, outDate);
217 }
218
GetNotAfterTime(HcfX509Certificate * self,CfBlob * outDate)219 static CfResult GetNotAfterTime(HcfX509Certificate *self, CfBlob *outDate)
220 {
221 if ((self == NULL) || (outDate == NULL)) {
222 LOGE("Invalid input parameter.");
223 return CF_INVALID_PARAMS;
224 }
225 if (!CfIsClassMatch((CfObjectBase *)self, GetX509CertificateClass())) {
226 LOGE("Class is not match.");
227 return CF_INVALID_PARAMS;
228 }
229 return ((HcfX509CertificateImpl *)self)->spiObj->engineGetNotAfterTime(
230 ((HcfX509CertificateImpl *)self)->spiObj, outDate);
231 }
232
GetSignature(HcfX509Certificate * self,CfBlob * sigOut)233 static CfResult GetSignature(HcfX509Certificate *self, CfBlob *sigOut)
234 {
235 if ((self == NULL) || (sigOut == NULL)) {
236 LOGE("Invalid input parameter.");
237 return CF_INVALID_PARAMS;
238 }
239 if (!CfIsClassMatch((CfObjectBase *)self, GetX509CertificateClass())) {
240 LOGE("Class is not match.");
241 return CF_INVALID_PARAMS;
242 }
243 return ((HcfX509CertificateImpl *)self)->spiObj->engineGetSignature(
244 ((HcfX509CertificateImpl *)self)->spiObj, sigOut);
245 }
246
GetSignatureAlgName(HcfX509Certificate * self,CfBlob * outName)247 static CfResult GetSignatureAlgName(HcfX509Certificate *self, CfBlob *outName)
248 {
249 if ((self == NULL) || (outName == NULL)) {
250 LOGE("Invalid input parameter.");
251 return CF_INVALID_PARAMS;
252 }
253 if (!CfIsClassMatch((CfObjectBase *)self, GetX509CertificateClass())) {
254 LOGE("Class is not match.");
255 return CF_INVALID_PARAMS;
256 }
257 return ((HcfX509CertificateImpl *)self)->spiObj->engineGetSignatureAlgName(
258 ((HcfX509CertificateImpl *)self)->spiObj, outName);
259 }
260
GetSignatureAlgOid(HcfX509Certificate * self,CfBlob * out)261 static CfResult GetSignatureAlgOid(HcfX509Certificate *self, CfBlob *out)
262 {
263 if ((self == NULL) || (out == NULL)) {
264 LOGE("Invalid input parameter.");
265 return CF_INVALID_PARAMS;
266 }
267 if (!CfIsClassMatch((CfObjectBase *)self, GetX509CertificateClass())) {
268 LOGE("Class is not match.");
269 return CF_INVALID_PARAMS;
270 }
271 return ((HcfX509CertificateImpl *)self)->spiObj->engineGetSignatureAlgOid(
272 ((HcfX509CertificateImpl *)self)->spiObj, out);
273 }
274
GetSignatureAlgParams(HcfX509Certificate * self,CfBlob * sigAlgParamsOut)275 static CfResult GetSignatureAlgParams(HcfX509Certificate *self, CfBlob *sigAlgParamsOut)
276 {
277 if ((self == NULL) || (sigAlgParamsOut == NULL)) {
278 LOGE("Invalid input parameter.");
279 return CF_INVALID_PARAMS;
280 }
281 if (!CfIsClassMatch((CfObjectBase *)self, GetX509CertificateClass())) {
282 LOGE("Class is not match.");
283 return CF_INVALID_PARAMS;
284 }
285 return ((HcfX509CertificateImpl *)self)->spiObj->engineGetSignatureAlgParams(
286 ((HcfX509CertificateImpl *)self)->spiObj, sigAlgParamsOut);
287 }
288
GetKeyUsage(HcfX509Certificate * self,CfBlob * boolArr)289 static CfResult GetKeyUsage(HcfX509Certificate *self, CfBlob *boolArr)
290 {
291 if ((self == NULL) || (boolArr == NULL)) {
292 LOGE("Invalid input parameter.");
293 return CF_INVALID_PARAMS;
294 }
295 if (!CfIsClassMatch((CfObjectBase *)self, GetX509CertificateClass())) {
296 LOGE("Class is not match.");
297 return CF_INVALID_PARAMS;
298 }
299 return ((HcfX509CertificateImpl *)self)->spiObj->engineGetKeyUsage(
300 ((HcfX509CertificateImpl *)self)->spiObj, boolArr);
301 }
302
GetExtKeyUsage(HcfX509Certificate * self,CfArray * keyUsageOut)303 static CfResult GetExtKeyUsage(HcfX509Certificate *self, CfArray *keyUsageOut)
304 {
305 if ((self == NULL) || (keyUsageOut == NULL)) {
306 LOGE("Invalid input parameter.");
307 return CF_INVALID_PARAMS;
308 }
309 if (!CfIsClassMatch((CfObjectBase *)self, GetX509CertificateClass())) {
310 LOGE("Class is not match.");
311 return CF_INVALID_PARAMS;
312 }
313 return ((HcfX509CertificateImpl *)self)->spiObj->engineGetExtKeyUsage(
314 ((HcfX509CertificateImpl *)self)->spiObj, keyUsageOut);
315 }
316
GetBasicConstraints(HcfX509Certificate * self)317 static int32_t GetBasicConstraints(HcfX509Certificate *self)
318 {
319 if (self == NULL) {
320 LOGE("Invalid input parameter.");
321 return INVALID_CONSTRAINTS_LEN;
322 }
323 if (!CfIsClassMatch((CfObjectBase *)self, GetX509CertificateClass())) {
324 LOGE("Class is not match.");
325 return INVALID_CONSTRAINTS_LEN;
326 }
327 return ((HcfX509CertificateImpl *)self)->spiObj->engineGetBasicConstraints(
328 ((HcfX509CertificateImpl *)self)->spiObj);
329 }
330
GetSubjectAltNames(HcfX509Certificate * self,CfArray * outName)331 static CfResult GetSubjectAltNames(HcfX509Certificate *self, CfArray *outName)
332 {
333 if ((self == NULL) || (outName == NULL)) {
334 LOGE("Invalid input parameter.");
335 return CF_INVALID_PARAMS;
336 }
337 if (!CfIsClassMatch((CfObjectBase *)self, GetX509CertificateClass())) {
338 LOGE("Class is not match.");
339 return CF_INVALID_PARAMS;
340 }
341 return ((HcfX509CertificateImpl *)self)->spiObj->engineGetSubjectAltNames(
342 ((HcfX509CertificateImpl *)self)->spiObj, outName);
343 }
344
GetIssuerAltNames(HcfX509Certificate * self,CfArray * outName)345 static CfResult GetIssuerAltNames(HcfX509Certificate *self, CfArray *outName)
346 {
347 if ((self == NULL) || (outName == NULL)) {
348 LOGE("Invalid input parameter.");
349 return CF_INVALID_PARAMS;
350 }
351 if (!CfIsClassMatch((CfObjectBase *)self, GetX509CertificateClass())) {
352 LOGE("Class is not match.");
353 return CF_INVALID_PARAMS;
354 }
355 return ((HcfX509CertificateImpl *)self)->spiObj->engineGetIssuerAltNames(
356 ((HcfX509CertificateImpl *)self)->spiObj, outName);
357 }
358
GetCRLDistributionPointsURI(HcfX509Certificate * self,CfArray * outURI)359 static CfResult GetCRLDistributionPointsURI(HcfX509Certificate *self, CfArray *outURI)
360 {
361 if ((self == NULL) || (outURI == NULL)) {
362 LOGE("crl dp invalid input parameter.");
363 return CF_INVALID_PARAMS;
364 }
365 if (!CfIsClassMatch((CfObjectBase *)self, GetX509CertificateClass())) {
366 LOGE("crl dp class is not match.");
367 return CF_INVALID_PARAMS;
368 }
369 return ((HcfX509CertificateImpl *)self)->spiObj->engineGetCRLDistributionPointsURI(
370 ((HcfX509CertificateImpl *)self)->spiObj, outURI);
371 }
372
Match(HcfX509Certificate * self,const HcfX509CertMatchParams * matchParams,bool * out)373 static CfResult Match(HcfX509Certificate *self, const HcfX509CertMatchParams *matchParams, bool *out)
374 {
375 if ((self == NULL) || (out == NULL) || (matchParams == NULL)) {
376 LOGE("Invalid input parameter.");
377 return CF_INVALID_PARAMS;
378 }
379 if (!CfIsClassMatch((CfObjectBase *)self, GetX509CertificateClass())) {
380 LOGE("Class is not match.");
381 return CF_INVALID_PARAMS;
382 }
383 return ((HcfX509CertificateImpl *)self)->spiObj->engineMatch(
384 ((HcfX509CertificateImpl *)self)->spiObj, matchParams, out);
385 }
386
ToString(HcfX509Certificate * self,CfBlob * out)387 static CfResult ToString(HcfX509Certificate *self, CfBlob *out)
388 {
389 if (self == NULL || out == NULL) {
390 LOGE("Invalid input parameter.");
391 return CF_INVALID_PARAMS;
392 }
393 if (!CfIsClassMatch((CfObjectBase *)self, GetX509CertificateClass())) {
394 LOGE("Class is not match.");
395 return CF_INVALID_PARAMS;
396 }
397 return ((HcfX509CertificateImpl *)self)->spiObj->engineToString(
398 ((HcfX509CertificateImpl *)self)->spiObj, out);
399 }
400
HashCode(HcfX509Certificate * self,CfBlob * out)401 static CfResult HashCode(HcfX509Certificate *self, CfBlob *out)
402 {
403 if (self == NULL || out == NULL) {
404 LOGE("Invalid input parameter.");
405 return CF_INVALID_PARAMS;
406 }
407 if (!CfIsClassMatch((CfObjectBase *)self, GetX509CertificateClass())) {
408 LOGE("Class is not match.");
409 return CF_INVALID_PARAMS;
410 }
411 return ((HcfX509CertificateImpl *)self)->spiObj->engineHashCode(
412 ((HcfX509CertificateImpl *)self)->spiObj, out);
413 }
414
GetExtensionsObject(HcfX509Certificate * self,CfBlob * out)415 static CfResult GetExtensionsObject(HcfX509Certificate *self, CfBlob *out)
416 {
417 if (self == NULL || out == NULL) {
418 LOGE("Invalid input parameter.");
419 return CF_INVALID_PARAMS;
420 }
421 if (!CfIsClassMatch((CfObjectBase *)self, GetX509CertificateClass())) {
422 LOGE("Class is not match.");
423 return CF_INVALID_PARAMS;
424 }
425 return ((HcfX509CertificateImpl *)self)->spiObj->engineGetExtensionsObject(
426 ((HcfX509CertificateImpl *)self)->spiObj, out);
427 }
428
HcfX509CertificateImplPack(HcfX509CertificateImpl * x509CertImpl,HcfX509CertificateSpi * spiObj)429 static void HcfX509CertificateImplPack(HcfX509CertificateImpl *x509CertImpl, HcfX509CertificateSpi *spiObj)
430 {
431 x509CertImpl->base.base.base.getClass = GetX509CertificateClass;
432 x509CertImpl->base.base.base.destroy = DestroyX509Certificate;
433 x509CertImpl->base.base.verify = Verify;
434 x509CertImpl->base.base.getEncoded = GetEncoded;
435 x509CertImpl->base.base.getPublicKey = GetPublicKey;
436 x509CertImpl->base.checkValidityWithDate = CheckValidityWithDate;
437 x509CertImpl->base.getVersion = GetVersion;
438 x509CertImpl->base.getSerialNumber = GetSerialNumber;
439 x509CertImpl->base.getIssuerName = GetIssuerName;
440 x509CertImpl->base.getSubjectName = GetSubjectName;
441 x509CertImpl->base.getSubjectNameEx = GetSubjectNameEx;
442 x509CertImpl->base.getNotBeforeTime = GetNotBeforeTime;
443 x509CertImpl->base.getNotAfterTime = GetNotAfterTime;
444 x509CertImpl->base.getSignature = GetSignature;
445 x509CertImpl->base.getSignatureAlgName = GetSignatureAlgName;
446 x509CertImpl->base.getSignatureAlgOid = GetSignatureAlgOid;
447 x509CertImpl->base.getSignatureAlgParams = GetSignatureAlgParams;
448 x509CertImpl->base.getKeyUsage = GetKeyUsage;
449 x509CertImpl->base.getExtKeyUsage = GetExtKeyUsage;
450 x509CertImpl->base.getBasicConstraints = GetBasicConstraints;
451 x509CertImpl->base.getSubjectAltNames = GetSubjectAltNames;
452 x509CertImpl->base.getIssuerAltNames = GetIssuerAltNames;
453 x509CertImpl->base.getCRLDistributionPointsURI = GetCRLDistributionPointsURI;
454 x509CertImpl->base.match = Match;
455 x509CertImpl->base.toString = ToString;
456 x509CertImpl->base.hashCode = HashCode;
457 x509CertImpl->base.getExtensionsObject = GetExtensionsObject;
458 x509CertImpl->spiObj = spiObj;
459 }
460
HcfX509CertificateCreate(const CfEncodingBlob * inStream,HcfX509Certificate ** returnObj)461 CfResult HcfX509CertificateCreate(const CfEncodingBlob *inStream, HcfX509Certificate **returnObj)
462 {
463 if ((inStream == NULL) || (inStream->len > HCF_MAX_BUFFER_LEN) || (returnObj == NULL)) {
464 return CF_INVALID_PARAMS;
465 }
466 const HcfX509CertificateFuncSet *funcSet = FindAbility("X509");
467 if (funcSet == NULL) {
468 return CF_NOT_SUPPORT;
469 }
470 HcfX509CertificateSpi *spiObj = NULL;
471 CfResult res = funcSet->createFunc(inStream, &spiObj);
472 if (res != CF_SUCCESS) {
473 LOGE("Failed to create spi object!");
474 return res;
475 }
476 HcfX509CertificateImpl *x509CertImpl = (HcfX509CertificateImpl *)CfMalloc(sizeof(HcfX509CertificateImpl), 0);
477 if (x509CertImpl == NULL) {
478 LOGE("Failed to allocate x509CertImpl memory!");
479 CfObjDestroy(spiObj);
480 return CF_ERR_MALLOC;
481 }
482 HcfX509CertificateImplPack(x509CertImpl, spiObj);
483 *returnObj = (HcfX509Certificate *)x509CertImpl;
484 return CF_SUCCESS;
485 }
486
HcfX509CertificateGenCsr(PrivateKeyInfo * privateKey,const HcfGenCsrConf * conf,CfBlob * csrBlob)487 CfResult HcfX509CertificateGenCsr(PrivateKeyInfo *privateKey, const HcfGenCsrConf *conf, CfBlob *csrBlob)
488 {
489 if (privateKey == NULL || conf == NULL || csrBlob == NULL) {
490 return CF_INVALID_PARAMS;
491 }
492
493 CfResult ret = GenerateX509Csr(privateKey, conf, csrBlob);
494 if (ret != CF_SUCCESS) {
495 LOGE("Generate CSR failed, ret: %d", ret);
496 return ret;
497 }
498 return CF_SUCCESS;
499 }