• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2025 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 "cert_manager_uri.h"
17 
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 
22 #include "securec.h"
23 
24 #include "cm_log.h"
25 #include "cm_util.h"
26 
27 #ifdef __cplusplus
28 extern "C" {
29 #endif
30 
31 #define IS_TYPE_VALID(t) ((t) <= CM_URI_TYPE_MAX)
32 
33 #define SCHEME "oh:"
34 #define P_OBJECT "o="
35 #define P_TYPE "t="
36 #define P_USER "u="
37 #define P_APP "a="
38 #define Q_MAC "m="
39 #define Q_CLIENT_USER "cu="
40 #define Q_CLIENT_APP "ca="
41 
42 // characters do not need to be encoded in path, other than digits and algabets
43 #define P_RES_AVAIL "-._~:[]@!$'()*+,=&"
44 // characters do not need to be encoded in query, other than digits and algabets
45 #define Q_RES_AVAIL "-._~:[]@!$'()*+,=/?|"
46 
47 // LCOV_EXCL_START
CertManagerFreeUri(struct CMUri * uri)48 int32_t CertManagerFreeUri(struct CMUri *uri)
49 {
50     if (uri == NULL) {
51         return CMR_OK;
52     }
53     CM_FREE_PTR(uri->object);
54     CM_FREE_PTR(uri->user);
55     CM_FREE_PTR(uri->app);
56     CM_FREE_PTR(uri->mac);
57     CM_FREE_PTR(uri->clientUser);
58     CM_FREE_PTR(uri->clientApp);
59     return CMR_OK;
60 }
61 
CertManagerIsKeyObjectType(uint32_t type)62 inline bool CertManagerIsKeyObjectType(uint32_t type)
63 {
64     return (type == CM_URI_TYPE_APP_KEY || type == CM_URI_TYPE_WLAN_KEY);
65 }
66 
IsUnreserved(const char * resAvail,size_t resAvailLen,char c)67 static int IsUnreserved(const char *resAvail, size_t resAvailLen, char c)
68 {
69     if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')) {
70         return 1;
71     }
72     if (resAvail != NULL) {
73         for (size_t i = 0; i < resAvailLen; i++) {
74             if (c == resAvail[i]) {
75                 return 1;
76             }
77         }
78     }
79     return 0;
80 }
81 
GetComponentEncodedLen(const char * key,const char * value,const char * resAvail,uint32_t * sep)82 static uint32_t GetComponentEncodedLen(const char *key, const char *value,
83     const char *resAvail, uint32_t *sep)
84 {
85     if (value == NULL) {
86         return 0;
87     }
88     size_t resAvailLen = strlen(resAvail);
89     size_t keyLen = strlen(key);
90     size_t valueLen = strlen(value);
91     size_t reserved = 0;
92     for (size_t i = 0; i < valueLen; i++) {
93         if (!IsUnreserved(resAvail, resAvailLen, value[i])) {
94             reserved++;
95         }
96     }
97     // each reserved character requires 2 extra bytes to percent-encode
98     uint32_t len = (uint32_t) (keyLen + valueLen + reserved * 2 + *sep);
99     *sep = 1;
100     return len;
101 }
102 
GetEncodedLen(const struct CMUri * uri)103 static uint32_t GetEncodedLen(const struct CMUri *uri)
104 {
105     if (uri == NULL) {
106         return 0;
107     }
108 
109     uint32_t sep = 0;
110     uint32_t len = strlen(SCHEME);
111 
112     len += GetComponentEncodedLen(P_TYPE, g_types[uri->type], P_RES_AVAIL, &sep);
113     len += GetComponentEncodedLen(P_OBJECT, uri->object, P_RES_AVAIL, &sep);
114     len += GetComponentEncodedLen(P_USER, uri->user, P_RES_AVAIL, &sep);
115     len += GetComponentEncodedLen(P_APP, uri->app, P_RES_AVAIL, &sep);
116 
117     uint32_t qlen = 0;
118     sep = 0;
119     qlen += GetComponentEncodedLen(Q_CLIENT_USER, uri->clientUser, Q_RES_AVAIL, &sep);
120     qlen += GetComponentEncodedLen(Q_CLIENT_APP, uri->clientApp, Q_RES_AVAIL, &sep);
121     qlen += GetComponentEncodedLen(Q_MAC, uri->mac, Q_RES_AVAIL, &sep);
122 
123     return len + sep + qlen;
124 }
125 
126 // encode the last 4 bits of an integer to a hex char
HexEncode(uint32_t v)127 static inline uint32_t HexEncode(uint32_t v)
128 {
129     v &= 0xf;
130     if (v < DEC_LEN) {
131         return ('0' + v);
132     } else {
133         return ('A' + v - DEC_LEN);
134     }
135 }
136 
EncodeComp(char * buf,uint32_t * offset,uint32_t * available,const char * key,const char * value,const char * resAvail,uint32_t * sep,char sepChar)137 static int32_t EncodeComp(
138     char *buf, uint32_t *offset, uint32_t *available,
139     const char *key, const char *value,
140     const char *resAvail,
141     uint32_t *sep, char sepChar)
142 {
143     if (value == NULL) {
144         return CMR_OK;
145     }
146 
147     size_t resAvailLen = strlen(resAvail);
148     size_t keyLen = strlen(key);
149     size_t valueLen = strlen(value);
150     uint32_t off = *offset;
151     uint32_t avail = *available;
152 
153     if (avail < *sep + keyLen + valueLen) {
154         return CMR_ERROR;
155     }
156 
157     if (*sep) {
158         buf[off] = sepChar;
159         off++;
160     }
161 
162     if (memcpy_s(buf + off, avail, key, keyLen) != EOK) {
163         return CMR_ERROR;
164     }
165     off += keyLen;
166     avail -= keyLen;
167 
168     for (size_t i = 0; i < valueLen; i++) {
169         if (IsUnreserved(resAvail, resAvailLen, value[i])) {
170             if (avail < 1) {
171                 return CMR_ERROR;
172             }
173             buf[off] = value[i];
174             off++;
175             avail--;
176         } else {
177             // each percent-encoded character requires 3 bytes
178             if (avail < 3) {
179                 return CMR_ERROR;
180             }
181             buf[off] = '%';
182             off++;
183             buf[off] = (char) HexEncode(value[i] >> 4); // higher 4 bits of the char byte
184             off++;
185             buf[off] = (char) HexEncode(value[i]); // lower 4 bits of the char byte
186             off++;
187             // each percent-encoded character requires 3 bytes
188             avail -= 3;
189         }
190     }
191 
192     *sep = 1;
193     *offset = off;
194     *available = avail;
195     return CMR_OK;
196 }
197 
EncodePathComp(char * encoded,uint32_t * offset,uint32_t * availLen,const struct CMUri * uri)198 static int32_t EncodePathComp(char *encoded, uint32_t *offset, uint32_t *availLen,
199     const struct CMUri *uri)
200 {
201     int32_t ret = CM_FAILURE;
202     uint32_t sep = 0;
203     uint32_t off = *offset;
204     uint32_t avail = *availLen;
205 
206     do {
207         ret = EncodeComp(encoded, &off, &avail, P_TYPE, g_types[uri->type], P_RES_AVAIL, &sep, ';');
208         if (ret != CM_SUCCESS) {
209             CM_LOG_E("encode <t=> failed");
210             break;
211         }
212 
213         ret = EncodeComp(encoded, &off, &avail, P_OBJECT, uri->object, P_RES_AVAIL, &sep, ';');
214         if (ret != CM_SUCCESS) {
215             CM_LOG_E("encode <o=> failed");
216             break;
217         }
218 
219         ret = EncodeComp(encoded, &off, &avail, P_USER, uri->user, P_RES_AVAIL, &sep, ';');
220         if (ret != CM_SUCCESS) {
221             CM_LOG_E("encode <u=> failed");
222             break;
223         }
224 
225         ret = EncodeComp(encoded, &off, &avail, P_APP, uri->app, P_RES_AVAIL, &sep, ';');
226         if (ret != CM_SUCCESS) {
227             CM_LOG_E("encode <a=> failed");
228             break;
229         }
230     } while (0);
231 
232     *offset = off;
233     *availLen = avail;
234     return ret;
235 }
236 
EncodeQueryComp(char * encoded,uint32_t * offset,uint32_t * availLen,const struct CMUri * uri)237 static int32_t EncodeQueryComp(char *encoded, uint32_t *offset, uint32_t *availLen,
238     const struct CMUri *uri)
239 {
240     if (uri->clientUser == NULL && uri->clientApp == NULL && uri->mac == NULL) {
241         // no query. we are done.
242         return CM_SUCCESS;
243     }
244 
245     int32_t ret = CM_FAILURE;
246     uint32_t sep = 0;
247     uint32_t off = *offset;
248     uint32_t avail = *availLen;
249     encoded[off] = '?';
250     off++;
251     avail--;
252 
253     do {
254         ret = EncodeComp(encoded, &off, &avail, Q_CLIENT_USER, uri->clientUser, Q_RES_AVAIL, &sep, '&');
255         if (ret != CM_SUCCESS) {
256             CM_LOG_E("encode <cu=> failed");
257             break;
258         }
259 
260         ret = EncodeComp(encoded, &off, &avail, Q_CLIENT_APP, uri->clientApp, Q_RES_AVAIL, &sep, '&');
261         if (ret != CM_SUCCESS) {
262             CM_LOG_E("encode <ca=> failed");
263             break;
264         }
265 
266         ret = EncodeComp(encoded, &off, &avail, Q_MAC, uri->mac, Q_RES_AVAIL, &sep, '&');
267         if (ret != CM_SUCCESS) {
268             CM_LOG_E("encode <m=> failed");
269             break;
270         }
271     } while (0);
272 
273     *offset = off;
274     *availLen = avail;
275     return ret;
276 }
277 
CertManagerUriEncode(char * encoded,uint32_t * encodedLen,const struct CMUri * uri)278 int32_t CertManagerUriEncode(char *encoded, uint32_t *encodedLen, const struct CMUri *uri)
279 {
280     if (encodedLen == NULL || uri == NULL || !IS_TYPE_VALID(uri->type)) {
281         CM_LOG_E("input params is invaild");
282         return CMR_ERROR_INVALID_ARGUMENT;
283     }
284 
285     uint32_t encLen = GetEncodedLen(uri) + 1;
286     if (encoded == NULL) {
287         *encodedLen = encLen;
288         return CM_SUCCESS;
289     }
290 
291     if (*encodedLen < encLen) {
292         CM_LOG_W("Buffer to small for encoded URI (%u < %u).\n", *encodedLen, encLen);
293         return CMR_ERROR_BUFFER_TOO_SMALL;
294     }
295 
296     uint32_t off = 0;
297     uint32_t avail = *encodedLen;
298 
299     if (memcpy_s(encoded, avail, SCHEME, strlen(SCHEME)) != EOK) {
300         return CMR_ERROR_MEM_OPERATION_COPY;
301     }
302     off += strlen(SCHEME);
303     avail -= strlen(SCHEME);
304 
305     int32_t ret = EncodePathComp(encoded, &off, &avail, uri);
306     if (ret != CM_SUCCESS) {
307         return ret;
308     }
309 
310     ret = EncodeQueryComp(encoded, &off, &avail, uri);
311     if (ret != CM_SUCCESS) {
312         return ret;
313     }
314 
315     *encodedLen = off;
316     return CM_SUCCESS;
317 }
318 
HexDecode(uint32_t h)319 static uint32_t HexDecode(uint32_t h)
320 {
321     h &= 0xff;
322     if (h >= '0' && h <= '9') {
323         return h - '0';
324     }
325     if (h >= 'a' && h <= 'f') {
326         return h - 'a' + DEC_LEN;
327     }
328     if (h >= 'A' && h <= 'F') {
329         return h - 'A' + DEC_LEN;
330     }
331     return 0;
332 }
333 
HexDecode2(uint32_t h1,uint32_t h2)334 static inline uint32_t HexDecode2(uint32_t h1, uint32_t h2)
335 {
336     return ((HexDecode(h1) << 4) | HexDecode(h2)) & 0xff; /* 4 is number of shifts */
337 }
338 
IndexOf(char sep,const char * data,uint32_t start,uint32_t end)339 static inline uint32_t IndexOf(char sep, const char *data, uint32_t start, uint32_t end)
340 {
341     for (uint32_t i = start; i < end; i++) {
342         if (data[i] == sep) {
343             return i;
344         }
345     }
346     return end;
347 }
348 
DecodeValue(const char * s,uint32_t off,uint32_t len)349 static char *DecodeValue(const char *s, uint32_t off, uint32_t len)
350 {
351     if (s == NULL || len == 0 || len > MAX_AUTH_LEN_URI) {
352         CM_LOG_E("input value failed");
353         return NULL;
354     }
355     char *buf = MALLOC(len + 1);
356     if (buf == NULL) {
357         CM_LOG_E("malloc buf failed");
358         return NULL;
359     }
360     (void)memset_s(buf, len + 1, 0, len + 1);
361 
362     uint32_t bufOff = 0;
363     for (uint32_t i = off; i < off + len; i++, bufOff++) {
364         if (s[i] != '%') {
365             buf[bufOff] = s[i];
366         } else if ((i + 2) < (off + len)) { /* 2 is to be accessed byte count */
367             buf[bufOff] = HexDecode2(s[i + 1], s[i + 2]); /* 2 is array index */
368             i += 2; /* 2 is array index */
369         } else {
370             CM_LOG_E("path has special character, but len is invalid");
371             free(buf);
372             return NULL;
373         }
374     }
375     char *ret = strndup(buf, bufOff);
376     free(buf);
377     return ret;
378 }
379 
DecodeEnum(const char * s,uint32_t off,uint32_t len,const char * values[],uint32_t valueCount)380 static uint32_t DecodeEnum(const char *s, uint32_t off, uint32_t len, const char *values[], uint32_t valueCount)
381 {
382     for (uint32_t i = 0; i < valueCount; i++) {
383         size_t valLen = strlen(values[i]);
384         if (valLen == len && memcmp(s + off, values[i], len) == 0) {
385             return i;
386         }
387     }
388     // no match found, default value is an invalid enum value
389     return valueCount + 1;
390 }
391 
DecodePath(struct CMUri * uri,const char * path,uint32_t start,uint32_t end)392 static int32_t DecodePath(struct CMUri *uri, const char *path, uint32_t start, uint32_t end)
393 {
394     while (start < end) {
395         uint32_t i = IndexOf(';', path, start, end);
396         if (i <= start) {
397             // something is wrong
398             CM_LOG_W("Invalid uri path\n");
399             return CMR_ERROR_INVALID_ARGUMENT_URI;
400         }
401 
402         uint32_t valueOff = 0;
403         uint32_t valueLen = 0;
404 
405         // for string field
406         char **field = NULL;
407 
408         // for enum field
409         uint32_t *e = NULL;
410         const char **values = NULL;
411         uint32_t valueCount = 0;
412 
413         if (!strncmp(P_OBJECT, path + start, strlen(P_OBJECT))) {
414             valueOff = start + strlen(P_OBJECT);
415             valueLen = i - start - strlen(P_OBJECT);
416             field = &uri->object;
417         } else if (!strncmp(P_TYPE, path + start, strlen(P_TYPE))) {
418             valueOff = start + strlen(P_TYPE);
419             valueLen = i - start - strlen(P_TYPE);
420             e = &uri->type;
421             values = g_types;
422             valueCount = TYPE_COUNT;
423         } else if (!strncmp(P_USER, path + start, strlen(P_USER))) {
424             valueOff = start + strlen(P_USER);
425             valueLen = i - start - strlen(P_USER);
426             field = &uri->user;
427         } else if (!strncmp(P_APP, path + start, strlen(P_APP))) {
428             valueOff = start + strlen(P_APP);
429             valueLen = i - start - strlen(P_APP);
430             field = &uri->app;
431         }
432 
433         if (field != NULL) {
434             if (valueLen == 0) {
435                 *field = NULL;
436             } else {
437                 *field = DecodeValue(path, valueOff, valueLen);
438             }
439         } else if (e != NULL) {
440             *e = DecodeEnum(path, valueOff, valueLen, values, valueCount);
441         } else {
442             CM_LOG_W("Invalid field in path\n");
443             return CMR_ERROR_INVALID_ARGUMENT_URI;
444         }
445 
446         start = i + 1;
447     }
448 
449     return CMR_OK;
450 }
451 
DecodeQuery(struct CMUri * uri,const char * query,uint32_t start,uint32_t end)452 static int32_t DecodeQuery(struct CMUri *uri, const char *query, uint32_t start, uint32_t end)
453 {
454     while (start < end) {
455         uint32_t i = IndexOf('&', query, start, end);
456         if (i <= start) {
457             // something is wrong
458             CM_LOG_W("Invalid uri query\n");
459             return CMR_ERROR_INVALID_ARGUMENT_URI;
460         }
461 
462         uint32_t valueOff = 0;
463         uint32_t valueLen = 0;
464         char **field = NULL;
465         if (!strncmp(Q_CLIENT_USER, query + start, strlen(Q_CLIENT_USER))) {
466             valueOff = start + strlen(Q_CLIENT_USER);
467             valueLen = i - start - strlen(Q_CLIENT_USER);
468             field = &uri->clientUser;
469         } else if (!strncmp(Q_CLIENT_APP, query + start, strlen(Q_CLIENT_APP))) {
470             valueOff = start + strlen(Q_CLIENT_APP);
471             valueLen = i - start - strlen(Q_CLIENT_APP);
472             field = &uri->clientApp;
473         } else if (!strncmp(Q_MAC, query + start, strlen(Q_MAC))) {
474             valueOff = start + strlen(Q_MAC);
475             valueLen = i - start - strlen(Q_MAC);
476             field = &uri->mac;
477         }
478 
479         if (field != NULL) {
480             if (valueLen == 0) {
481                 *field = NULL;
482             } else {
483                 *field = DecodeValue(query, valueOff, valueLen);
484             }
485         } else {
486             CM_LOG_W("Invalid field in query\n");
487             return CMR_ERROR_INVALID_ARGUMENT_URI;
488         }
489 
490         start = i + 1;
491     }
492     return CMR_OK;
493 }
494 
CertManagerUriDecode(struct CMUri * uri,const char * encoded)495 int32_t CertManagerUriDecode(struct CMUri *uri, const char *encoded)
496 {
497     if (uri == NULL || encoded == NULL) {
498         CM_LOG_E("input params is invaild");
499         return CMR_ERROR_INVALID_ARGUMENT_URI;
500     }
501 
502     (void)memset_s(uri, sizeof(*uri), 0, sizeof(*uri));
503     uri->type = CM_URI_TYPE_INVALID;
504 
505     uint32_t len = strlen(encoded);
506     if (len > MAX_AUTH_LEN_URI) {
507         CM_LOG_E("invalid uri len[%u]", len);
508         return CMR_ERROR_INVALID_ARGUMENT_URI;
509     }
510 
511     uint32_t off = 0;
512     if (len < strlen(SCHEME) || memcmp(encoded, SCHEME, strlen(SCHEME))) {
513         CM_LOG_E("Scheme mismatch. Not a cert manager URI");
514         return CMR_ERROR_INVALID_ARGUMENT_URI;
515     }
516     off += strlen(SCHEME);
517 
518     uint32_t pathStart = off;
519     uint32_t pathEnd = IndexOf('?', encoded, off, len);
520     uint32_t queryStart = (pathEnd == len) ? len : pathEnd + 1;
521     uint32_t queryEnd = len;
522 
523     int32_t ret = DecodePath(uri, encoded, pathStart, pathEnd);
524     if (ret != CM_SUCCESS) {
525         CertManagerFreeUri(uri);
526         return ret;
527     }
528 
529     ret = DecodeQuery(uri, encoded, queryStart, queryEnd);
530     if (ret != CM_SUCCESS) {
531         CertManagerFreeUri(uri);
532         return ret;
533     }
534 
535     return CM_SUCCESS;
536 }
537 
CertManagerGetUidFromUri(const struct CmBlob * uri,uint32_t * uid)538 int32_t CertManagerGetUidFromUri(const struct CmBlob *uri, uint32_t *uid)
539 {
540     struct CMUri uriObj;
541     (void)memset_s(&uriObj, sizeof(uriObj), 0, sizeof(uriObj));
542     int32_t ret = CertManagerUriDecode(&uriObj, (char *)uri->data);
543     if (ret != CM_SUCCESS) {
544         CM_LOG_E("uri decode failed, ret = %d", ret);
545         return ret;
546     }
547 
548     if (uriObj.app == NULL) {
549         CM_LOG_E("uri app invalid");
550         (void)CertManagerFreeUri(&uriObj);
551         return CMR_ERROR_INVALID_ARGUMENT_URI;
552     }
553 
554     if (CmIsNumeric(uriObj.app, strlen(uriObj.app) + 1, uid) != CM_SUCCESS) {
555         CM_LOG_E("parse string to uint32 failed.");
556         (void)CertManagerFreeUri(&uriObj);
557         return CMR_ERROR_INVALID_ARGUMENT_URI;
558     }
559 
560     (void)CertManagerFreeUri(&uriObj);
561     return CM_SUCCESS;
562 }
563 
CmConstructUri(const struct CMUri * uriObj,struct CmBlob * outUri)564 int32_t CmConstructUri(const struct CMUri *uriObj, struct CmBlob *outUri)
565 {
566     uint32_t outLen = 0;
567     int32_t ret = CertManagerUriEncode(NULL, &outLen, uriObj);
568     if (ret != CM_SUCCESS) {
569         CM_LOG_E("get uriObj len failed, ret = %d", ret);
570         return ret;
571     }
572 
573     if ((outLen == 0) || (outLen > MAX_OUT_BLOB_SIZE)) {
574         CM_LOG_E("invalid outLen[%u]", outLen);
575         return CMR_ERROR_INVALID_ARGUMENT;
576     }
577 
578     char *data = (char *)CMMalloc(outLen);
579     if (data == NULL) {
580         CM_LOG_E("malloc uri buf failed");
581         return CMR_ERROR_MALLOC_FAIL;
582     }
583     (void)memset_s(data, outLen, 0, outLen);
584     outUri->size = outLen; /* include 1 byte: the terminator('\0')  */
585 
586     ret = CertManagerUriEncode(data, &outLen, uriObj); /* outLen not include '\0' */
587     if (ret != CM_SUCCESS) {
588         CM_LOG_E("encord uri failed");
589         outUri->size = 0;
590         CMFree(data);
591         return ret;
592     }
593 
594     outUri->data = (uint8_t *)data;
595     return CM_SUCCESS;
596 }
597 
UintToStr(uint32_t input,char * out,uint32_t outLen)598 static int32_t UintToStr(uint32_t input, char *out, uint32_t outLen)
599 {
600     if (snprintf_s(out, outLen, outLen - 1, "%u", input) < 0) {
601         return CMR_ERROR_MEM_OPERATION_PRINT;
602     }
603     return CM_SUCCESS;
604 }
605 
CmConstructCommonUri(const struct CmContext * context,const uint32_t type,const struct CmBlob * certAlias,struct CmBlob * outUri)606 int32_t CmConstructCommonUri(const struct CmContext *context, const uint32_t type,
607     const struct CmBlob *certAlias, struct CmBlob *outUri)
608 {
609     struct CMUri uriObj;
610     (void)memset_s(&uriObj, sizeof(struct CMUri), 0, sizeof(struct CMUri));
611 
612     char userIdStr[MAX_UINT32_LEN] = { 0 };
613     int32_t ret = UintToStr(context->userId, userIdStr, MAX_UINT32_LEN);
614     if (ret != CM_SUCCESS) {
615         CM_LOG_E("construct userId to str failed");
616         return ret;
617     }
618 
619     char uidStr[MAX_UINT32_LEN] = { 0 };
620     ret = UintToStr(context->uid, uidStr, MAX_UINT32_LEN);
621     if (ret != CM_SUCCESS) {
622         CM_LOG_E("construct uid to str failed");
623         return ret;
624     }
625 
626     uriObj.object = (char *)certAlias->data;
627     uriObj.type = type;
628     uriObj.user = userIdStr;
629     uriObj.app = uidStr;
630 
631     ret = CmConstructUri(&uriObj, outUri);
632     if (ret != CM_SUCCESS) {
633         CM_LOG_E("construct uri failed, ret = %d", ret);
634     }
635     return ret;
636 }
637 
638 #ifdef __cplusplus
639 }
640 #endif
641 // LCOV_EXCL_STOP
642