1/*
2 * Copyright (c) 2022 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 "dslm_msg_utils.h"
17
18#include <string.h>
19
20#include "securec.h"
21
22#include "device_security_defines.h"
23#include "dslm_core_defines.h"
24#include "dslm_credential.h"
25#include "utils_base64.h"
26#include "utils_hexstring.h"
27#include "utils_json.h"
28#include "utils_log.h"
29#include "utils_mem.h"
30
31#define CHALLENGE_STRING_LENGTH 32
32
33static uint8_t *GenerateSecInfoResponseJson(uint64_t challenge, const DslmCredBuff *cred)
34{
35    uint8_t *credBase64Str = NULL;
36    uint8_t *out = NULL;
37
38    DslmJsonHandle head = DslmCreateJson(NULL);
39    if (head == NULL) {
40        return NULL;
41    }
42
43    DslmJsonHandle body = DslmCreateJson(NULL);
44    if (body == NULL) {
45        DslmDestroyJson(head);
46        return NULL;
47    }
48
49    DslmAddFieldIntToJson(head, FIELD_MESSAGE, MSG_TYPE_DSLM_CRED_RESPONSE);
50    DslmAddFieldJsonToJson(head, FIELD_PAYLOAD, body);
51
52    DslmAddFieldIntToJson(body, FIELD_VERSION, (int32_t)GetCurrentVersion());
53    DslmAddFieldIntToJson(body, FIELD_CRED_TYPE, cred->type);
54
55    char challengeStr[CHALLENGE_STRING_LENGTH] = {0};
56    char *nonce = &challengeStr[0];
57    DslmByteToHexString((uint8_t *)&challenge, sizeof(challenge), (uint8_t *)nonce, CHALLENGE_STRING_LENGTH);
58    challengeStr[CHALLENGE_STRING_LENGTH - 1] = 0;
59    DslmAddFieldStringToJson(body, FIELD_CHALLENGE, nonce);
60
61    credBase64Str = Base64EncodeApp(cred->credVal, cred->credLen);
62    // it is ok when credBase64Str is NULL
63    DslmAddFieldStringToJson(body, FIELD_CRED_INFO, (char *)credBase64Str);
64    out = (uint8_t *)DslmConvertJsonToString(head);
65
66    if (head != NULL) {
67        DslmDestroyJson(head);
68        body = NULL; // no need to free body
69    }
70
71    if (body != NULL) {
72        DslmDestroyJson(body);
73    }
74    if (credBase64Str != NULL) {
75        FREE(credBase64Str);
76    }
77    return out;
78}
79
80static uint8_t *GenerateSecInfoRequestJson(uint64_t challenge)
81{
82    DslmJsonHandle head = DslmCreateJson(NULL);
83    if (head == NULL) {
84        return NULL;
85    }
86    DslmJsonHandle body = DslmCreateJson(NULL);
87    if (body == NULL) {
88        DslmDestroyJson(head);
89        return NULL;
90    }
91
92    char challengeStr[CHALLENGE_STRING_LENGTH] = {0};
93    char *nonce = &challengeStr[0];
94    DslmByteToHexString((uint8_t *)&challenge, sizeof(challenge), (uint8_t *)nonce, CHALLENGE_STRING_LENGTH);
95    challengeStr[CHALLENGE_STRING_LENGTH - 1] = 0;
96
97    DslmAddFieldIntToJson(head, FIELD_MESSAGE, MSG_TYPE_DSLM_CRED_REQUEST);
98    DslmAddFieldJsonToJson(head, FIELD_PAYLOAD, body);
99    DslmAddFieldIntToJson(body, FIELD_VERSION, (int32_t)GetCurrentVersion());
100
101    DslmAddFieldStringToJson(body, FIELD_CHALLENGE, nonce);
102
103    CredType credTypeArray[MAX_CRED_ARRAY_SIZE] = {0};
104    int32_t arraySize = GetSupportedCredTypes(credTypeArray, MAX_CRED_ARRAY_SIZE);
105    DslmAddFieldIntArrayToJson(body, FIELD_SUPPORT, (const int32_t *)credTypeArray, arraySize);
106
107    uint8_t *out = (uint8_t *)DslmConvertJsonToString(head);
108
109    if (head != NULL) {
110        DslmDestroyJson(head);
111        body = NULL; // no need to free body
112    }
113
114    if (body != NULL) {
115        DslmDestroyJson(body);
116    }
117    return out;
118}
119
120int32_t BuildDeviceSecInfoRequest(uint64_t challenge, MessageBuff **msg)
121{
122    if ((msg == NULL) || (*msg != NULL)) {
123        return ERR_INVALID_PARA;
124    }
125
126    MessageBuff *out = MALLOC(sizeof(MessageBuff));
127    if (out == NULL) {
128        return ERR_NO_MEMORY;
129    }
130    (void)memset_s(out, sizeof(MessageBuff), 0, sizeof(MessageBuff));
131
132    out->buff = GenerateSecInfoRequestJson(challenge);
133    if (out->buff == NULL) {
134        FREE(out);
135        return ERR_JSON_ERR;
136    }
137    out->length = strlen((char *)out->buff) + 1;
138    *msg = out;
139    return SUCCESS;
140}
141
142int32_t ParseDeviceSecInfoRequest(const MessageBuff *msg, RequestObject *obj)
143{
144    if (msg == NULL || obj == NULL || msg->buff == NULL) {
145        return ERR_INVALID_PARA;
146    }
147    SECURITY_LOG_DEBUG("ParseDeviceSecInfoRequest msg is %s", (char *)msg->buff);
148
149    DslmJsonHandle handle = DslmCreateJson((const char *)msg->buff);
150    if (handle == NULL) {
151        return ERR_INVALID_PARA;
152    }
153
154    const char *nonceStr = DslmGetJsonFieldString(handle, FIELD_CHALLENGE);
155    if (nonceStr == NULL) {
156        DslmDestroyJson(handle);
157        return ERR_NO_CHALLENGE;
158    }
159
160    int32_t ret = DslmHexStringToByte(nonceStr, strlen(nonceStr), (uint8_t *)&obj->challenge, sizeof(obj->challenge));
161    if (ret != 0) {
162        DslmDestroyJson(handle);
163        return ERR_NO_CHALLENGE;
164    }
165
166    obj->version = (uint32_t)DslmGetJsonFieldInt(handle, FIELD_VERSION);
167    obj->arraySize = DslmGetJsonFieldIntArray(handle, FIELD_SUPPORT, (int32_t *)obj->credArray, MAX_CRED_ARRAY_SIZE);
168
169    DslmDestroyJson(handle);
170
171    return SUCCESS;
172}
173
174int32_t BuildDeviceSecInfoResponse(uint64_t challenge, const DslmCredBuff *cred, MessageBuff **msg)
175{
176    if ((cred == NULL) || (msg == NULL) || (*msg != NULL)) {
177        return ERR_INVALID_PARA;
178    }
179    MessageBuff *out = MALLOC(sizeof(MessageBuff));
180    if (out == NULL) {
181        return ERR_NO_MEMORY;
182    }
183
184    out->buff = GenerateSecInfoResponseJson(challenge, cred);
185    if (out->buff == NULL) {
186        FREE(out);
187        return ERR_JSON_ERR;
188    }
189    out->length = strlen((char *)out->buff) + 1;
190
191    *msg = out;
192    return SUCCESS;
193}
194
195int32_t ParseDeviceSecInfoResponse(const MessageBuff *msg, uint64_t *challenge, uint32_t *version, DslmCredBuff **cred)
196{
197    if (msg == NULL || challenge == NULL || version == NULL || cred == NULL) {
198        return ERR_INVALID_PARA;
199    }
200
201    if (msg->buff == NULL || *cred != NULL) {
202        return ERR_INVALID_PARA;
203    }
204
205    DslmJsonHandle handle = DslmCreateJson((const char *)msg->buff);
206    if (handle == NULL) {
207        return ERR_INVALID_PARA;
208    }
209
210    const char *nonceStr = DslmGetJsonFieldString(handle, FIELD_CHALLENGE);
211    if (nonceStr == NULL) {
212        DslmDestroyJson(handle);
213        return ERR_NO_CHALLENGE;
214    }
215    uint64_t nonceNum = 0;
216    int32_t ret = DslmHexStringToByte(nonceStr, strlen(nonceStr), (uint8_t *)&nonceNum, sizeof(uint64_t));
217    if (ret != 0) {
218        DslmDestroyJson(handle);
219        return ERR_NO_CHALLENGE;
220    }
221
222    uint32_t type = (uint32_t)DslmGetJsonFieldInt(handle, FIELD_CRED_TYPE);
223    uint32_t verNum = (uint32_t)DslmGetJsonFieldInt(handle, FIELD_VERSION);
224
225    const char *credStr = DslmGetJsonFieldString(handle, FIELD_CRED_INFO);
226    if (credStr == NULL) {
227        DslmDestroyJson(handle);
228        return ERR_NO_CRED;
229    }
230
231    uint8_t *credBuf = NULL;
232    uint32_t credLen = (uint32_t)Base64DecodeApp((uint8_t *)credStr, &credBuf);
233    if (credBuf == NULL) {
234        DslmDestroyJson(handle);
235        return ERR_NO_CRED;
236    }
237
238    DslmCredBuff *out = CreateDslmCred((CredType)type, credLen, credBuf);
239    if (out == NULL) {
240        DslmDestroyJson(handle);
241        FREE(credBuf);
242        return ERR_NO_MEMORY;
243    }
244
245    DslmDestroyJson(handle);
246    FREE(credBuf);
247    *version = verNum;
248    *challenge = nonceNum;
249    *cred = out;
250    return SUCCESS;
251}
252