CRED payload conversion from JSON to CBOR
[platform/upstream/iotivity.git] / resource / csdk / security / provisioning / src / credentialgenerator.c
1 /* *****************************************************************
2  *
3  * Copyright 2015 Samsung Electronics All Rights Reserved.
4  *
5  *
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  * *****************************************************************/
20 #include <string.h>
21 #include "credentialgenerator.h"
22 #include "base64.h"
23 #include "oic_malloc.h"
24 #include "oic_string.h"
25 #include "ocpayload.h"
26 #include "payload_logging.h"
27 #include "credresource.h"
28 #include "ocrandom.h"
29 #include "srmutility.h"
30 #include "stdbool.h"
31 #include "securevirtualresourcetypes.h"
32 #ifdef __WITH_X509__
33 #include "ck_manager.h"
34
35 #define CHAIN_LEN (2) //TODO: replace by external define or a runtime value
36 #endif  //__WITH_X509__
37
38 #define TAG "SRPAPI-CG"
39
40 static const char OIC_JSON_CRV_NAME[] = "crv";
41 static const char OIC_JSON_KTY_NAME[] = "kty";
42 static const char OIC_JSON_CERTIFICATE_NAME[] = "x5c";
43 static const char OIC_JSON_D_NAME[] = "d";
44 static const char kty[] = "EC";
45 static const char crv[] = "P-256";
46 static const uint8_t CertMapSize = 3;
47
48 OCStackResult PMGeneratePairWiseCredentials(OicSecCredType_t type, size_t keySize,
49         const OicUuid_t *ptDeviceId, const OicUuid_t *firstDeviceId,
50         const OicUuid_t *secondDeviceId, OicSecCred_t **firstCred, OicSecCred_t **secondCred)
51 {
52     if (NULL == ptDeviceId || NULL == firstDeviceId || NULL != *firstCred || \
53         NULL == secondDeviceId || NULL != *secondCred)
54     {
55         OIC_LOG(INFO, TAG, "Invalid params");
56         return OC_STACK_INVALID_PARAM;
57     }
58     if(!(keySize == OWNER_PSK_LENGTH_128 || keySize == OWNER_PSK_LENGTH_256))
59     {
60         OIC_LOG(INFO, TAG, "Invalid key size");
61         return OC_STACK_INVALID_PARAM;
62     }
63     OCStackResult res = OC_STACK_ERROR;
64     OicSecCred_t *tempFirstCred = NULL;
65     OicSecCred_t *tempSecondCred = NULL;
66
67     size_t privDataKeySize = keySize;
68
69     uint8_t *privData = (uint8_t *)OICCalloc(privDataKeySize, sizeof(uint8_t));
70     VERIFY_NON_NULL(TAG, privData, ERROR);
71
72     OCFillRandomMem(privData, privDataKeySize);
73
74     // TODO: currently owner array is 1. only provisioning tool's id.
75     tempFirstCred =  GenerateCredential(secondDeviceId, type, NULL, privData, 1, ptDeviceId);
76     VERIFY_NON_NULL(TAG, tempFirstCred, ERROR);
77
78     // TODO: currently owner array is 1. only provisioning tool's id.
79     tempSecondCred =  GenerateCredential(firstDeviceId, type, NULL, privData, 1, ptDeviceId);
80     VERIFY_NON_NULL(TAG, tempSecondCred, ERROR);
81
82     *firstCred = tempFirstCred;
83     *secondCred = tempSecondCred;
84     res = OC_STACK_OK;
85
86 exit:
87     OICFree(privData);
88
89     if(res != OC_STACK_OK)
90     {
91         OICFree(tempFirstCred);
92         OICFree(tempSecondCred);
93         *firstCred = NULL;
94         *secondCred = NULL;
95     }
96
97     return res;
98 }
99
100 #ifdef __WITH_X509__
101 /**
102  * Function to compose JSON Web Key (JWK) string from a certificate and a public key.
103  *
104  * @param certificateChain    Array of Base64 encoded certificate strings.
105  * @param chainLength         Number of the certificates in certificateChain.
106  * @param payload Valid JWK CBOR on success, or NULL on fail.
107
108  */
109 static OCStackResult CreateCertificatePublicJWK(const char *const *certificateChain,
110        const size_t chainLength, uint8_t **cborPayload, size_t *size)
111 {
112     OCStackResult ret = OC_STACK_ERROR;
113     *cborPayload = NULL;
114     *size = 0;
115
116     if (NULL == certificateChain || chainLength == 0)
117     {
118         OIC_LOG(ERROR, TAG, "Error CreateCertificatePublicJWK: Invalid params");
119         return OC_STACK_INVALID_PARAM;
120     }
121
122     size_t certChainSize = 0;
123     for (size_t i = 0; i < chainLength; ++i)
124     {
125         if (NULL != certificateChain[i])
126         {
127             certChainSize += strlen(certificateChain[i]);
128         }
129         else
130         {
131             OIC_LOG(ERROR, TAG, "Error CreateCertificatePublicJWK: Invalid params");
132             return OC_STACK_INVALID_PARAM;
133         }
134     }
135
136     // cborArbitraryLen is a value to conver field names and cbor map, cbor array.
137     size_t cborArbitraryLen = 255;
138     size_t cborLen = certChainSize + cborArbitraryLen;
139     int64_t cborEncoderResult = CborNoError;
140     CborEncoder encoder = { .end = 0 };
141     uint8_t *outPayload = (uint8_t *)OICCalloc(1, cborLen);
142     VERIFY_NON_NULL(TAG, outPayload, ERROR);
143     cbor_encoder_init(&encoder, outPayload, cborLen, 0);
144
145     CborEncoder credMap = { .end = 0 };
146     cborEncoderResult |= cbor_encoder_create_map(&encoder, &credMap, CertMapSize);
147     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Cred Map.");
148
149     cborEncoderResult |= cbor_encode_text_string(&credMap, OIC_JSON_KTY_NAME,
150             strlen(OIC_JSON_KTY_NAME));
151     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding ");
152     cborEncoderResult |= cbor_encode_text_string(&credMap, kty, strlen(kty));
153     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding ");
154
155     cborEncoderResult |= cbor_encode_text_string(&credMap, OIC_JSON_CRV_NAME,
156             strlen(OIC_JSON_CRV_NAME));
157     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding ");
158     cborEncoderResult |= cbor_encode_text_string(&credMap, crv, strlen(crv));
159     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding ");
160
161     cborEncoderResult |= cbor_encode_text_string(&credMap, OIC_JSON_CERTIFICATE_NAME,
162             strlen(OIC_JSON_CERTIFICATE_NAME));
163     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Certificate Name.");
164     CborEncoder certs = { {.ptr = NULL }, .end = 0 };
165     cborEncoderResult |= cbor_encoder_create_array(&credMap, &certs, chainLength);
166     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Certificate Array.");
167     for (size_t i = 0; i < chainLength; i++)
168     {
169         cborEncoderResult |= cbor_encode_byte_string(&certs, (uint8_t *)certificateChain[i], strlen(certificateChain[i]));
170         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Certificate Chain.");
171     }
172     cborEncoderResult |= cbor_encoder_close_container(&credMap, &certs);
173     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing Certificate Chain.");
174
175     cborEncoderResult |= cbor_encoder_close_container(&encoder, &credMap);
176     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing Cred Map.");
177
178     *cborPayload = outPayload;
179     *size = encoder.ptr - outPayload;
180     ret = OC_STACK_OK;
181
182 exit:
183     return ret;
184 }
185
186 /**
187  * Function to compose JWK string from a private key.
188  *
189  * @param privateKey to be converted to CBOR.
190  * @ Valid JWK string on success, or NULL on fail.
191  */
192 OCStackResult CreateCertificatePrivateJWK(const char *privateKey, uint8_t **cborPayload,
193         size_t *size)
194 {
195     *cborPayload = NULL;
196     *size = 0;
197     OCStackResult ret = OC_STACK_INVALID_PARAM;
198     VERIFY_NON_NULL(TAG, privateKey, ERROR);
199
200     // cborArbitraryLen is a value to conver field names and cbor map, cbor array.
201     size_t cborArbitraryLen = 255;
202     size_t cborLen = strlen(privateKey) + cborArbitraryLen;
203     int64_t cborEncoderResult = CborNoError;
204     ret = OC_STACK_ERROR;
205     uint8_t *outPayload = (uint8_t *)OICCalloc(1, cborLen);
206     VERIFY_NON_NULL(TAG, outPayload, ERROR);
207
208     CborEncoder encoder = { .end = 0 };
209     cbor_encoder_init(&encoder, outPayload, cborLen, 0);
210
211     CborEncoder credMap = { .end = 0 };
212     cborEncoderResult |= cbor_encoder_create_map(&encoder, &credMap, 3);
213     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding ");
214
215     cborEncoderResult |= cbor_encode_text_string(&credMap, OIC_JSON_KTY_NAME,
216             strlen(OIC_JSON_KTY_NAME));
217     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding ");
218     cborEncoderResult |= cbor_encode_text_string(&credMap, kty, strlen(kty));
219     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding ");
220
221     cborEncoderResult |= cbor_encode_text_string(&credMap, OIC_JSON_CRV_NAME,
222             strlen(OIC_JSON_CRV_NAME));
223     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding ");
224     cborEncoderResult |= cbor_encode_text_string(&credMap, crv, strlen(crv));
225     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding ");
226
227     cborEncoderResult |= cbor_encode_text_string(&credMap, OIC_JSON_D_NAME,
228             strlen(OIC_JSON_D_NAME));
229     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding D tag.");
230     cborEncoderResult |= cbor_encode_byte_string(&credMap, (uint8_t *)privateKey, strlen(privateKey));
231     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding D Value.");
232
233     cborEncoderResult |= cbor_encoder_close_container(&encoder, &credMap);
234     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing Cred Map.");
235
236     *cborPayload = outPayload;
237     *size = encoder.ptr - outPayload;
238     ret = OC_STACK_OK;
239
240 exit:
241     return ret;
242 }
243
244 /**
245  * Function to generate Base64 encoded credential data for device.
246  *
247  * @param[in]   subject             Device id.
248  * @param[out]  certificateChain    Pointer to Array of Base64 encoded certificate strings.
249  * @param[out]  chainLength         Pointer to number of the certificates in certificateChain.
250  * @param[out]  privKey             Pointer to Base64 encoded private key.
251  * @return  OC_STACK_OK on success
252  */
253 static OCStackResult GenerateCertificateAndKeys(const OicUuid_t * subject, char *** const certificateChain,
254         size_t * const chainLength, char ** const privKey)
255 {
256     if (NULL == subject || NULL == certificateChain || NULL == chainLength || NULL == privKey)
257     {
258         return  OC_STACK_INVALID_PARAM;
259     }
260     *certificateChain = NULL;
261     *privKey     = NULL;
262
263     ByteArray pubKeyBA  = BYTE_ARRAY_INITIALIZER;
264     ByteArray privKeyBA = BYTE_ARRAY_INITIALIZER;
265     ByteArray cert[CHAIN_LEN];
266
267     uint8_t pubKeyData[PUBLIC_KEY_SIZE] = {0};
268     uint8_t privKeyData[PRIVATE_KEY_SIZE] = {0};
269     uint8_t certData[ISSUER_MAX_CERT_SIZE * CHAIN_LEN] = {0};
270     uint8_t subjName[UUID_LENGTH + 1] = {0};
271
272     pubKeyBA.data  = pubKeyData;
273     pubKeyBA.len   = PUBLIC_KEY_SIZE;
274     privKeyBA.data = privKeyData;
275     privKeyBA.len  = PRIVATE_KEY_SIZE;
276     for (size_t i = 0; i < CHAIN_LEN; ++i)
277     {
278         cert[i].data      = certData + ISSUER_MAX_CERT_SIZE * i;
279         cert[i].len       = ISSUER_MAX_CERT_SIZE;
280     }
281
282     memcpy(subjName, subject->id, UUID_LENGTH);
283     subjName[UUID_LENGTH] = '\0';
284
285     if (PKI_SUCCESS != GenerateKeyPair(&privKeyBA, &pubKeyBA))
286     {
287         OIC_LOG(ERROR, TAG, "Error generating keys.");
288         return OC_STACK_ERROR;
289     }
290     if (PKI_SUCCESS != CKMIssueDeviceCertificate(subjName, NULL, NULL, pubKeyBA.data, cert))
291     {
292         OIC_LOG(ERROR, TAG, "Error generating certificate.");
293         return OC_STACK_ERROR;
294     }
295
296     char privB64buf[B64ENCODE_OUT_SAFESIZE(PRIVATE_KEY_SIZE) + 1] = {0};
297     uint32_t privB64len = 0;
298     if (B64_OK != b64Encode(privKeyBA.data,  privKeyBA.len, privB64buf,
299                              B64ENCODE_OUT_SAFESIZE(PRIVATE_KEY_SIZE) + 1, &privB64len))
300     {
301         OIC_LOG(ERROR, TAG, "Error while encoding key");
302         return OC_STACK_ERROR;
303     }
304
305     if (PKI_SUCCESS != GetCAChain(chainLength , cert + 1))
306     {
307         OIC_LOG(ERROR, TAG, "Error getting CA certificate chain.");
308         return OC_STACK_ERROR;
309     }
310
311     ++(*chainLength);
312     *certificateChain = (char **)OICMalloc(sizeof(char *) * (*chainLength));
313
314     OCStackResult ret = OC_STACK_NO_MEMORY;
315     if (NULL == *certificateChain)
316     {
317         goto memclean;
318     }
319
320
321     for (size_t i = 0; i < *chainLength; ++i)
322     {
323         (*certificateChain)[i] = NULL;
324
325         char certB64buf[B64ENCODE_OUT_SAFESIZE(ISSUER_MAX_CERT_SIZE) + 1] = {0};
326         uint32_t certB64len = 0;
327         if (B64_OK != b64Encode(cert[i].data, cert[i].len, certB64buf,
328                                 B64ENCODE_OUT_SAFESIZE(ISSUER_MAX_CERT_SIZE) + 1, &certB64len))
329         {
330             OIC_LOG(ERROR, TAG, "Error while encoding certificate");
331             ret = OC_STACK_ERROR;
332             goto memclean;
333         }
334
335         (*certificateChain)[i] = (char *) OICMalloc(certB64len + 1);
336         if (NULL == (*certificateChain)[i])
337         {
338             goto memclean;
339         }
340
341         memcpy((*certificateChain)[i], certB64buf, certB64len + 1);
342     }
343
344
345     *privKey     = (char *)OICMalloc(privB64len + 1);
346
347     if (NULL == *privKey)
348     {
349 memclean:
350         if (NULL != *certificateChain)
351         {
352             for (size_t i = 0; i < *chainLength; ++i)
353             {
354                 OICFree((*certificateChain)[i]);
355             }
356         }
357         OICFree(*certificateChain);
358         *certificateChain = NULL;
359         *privKey     = NULL;
360         *chainLength = 0;
361         if (OC_STACK_NO_MEMORY == ret)
362         {
363             OIC_LOG(ERROR, TAG, "Error while memory allocation");
364         }
365         return ret;
366     }
367
368     memcpy(*privKey, privB64buf, privB64len + 1);
369
370     return OC_STACK_OK;
371 }
372
373 OCStackResult PMGenerateCertificateCredentials(const OicUuid_t *ptDeviceId,
374         const OicUuid_t *deviceId, OicSecCred_t **const cred)
375 {
376     if (NULL == ptDeviceId || NULL == deviceId || NULL == cred)
377     {
378         return OC_STACK_INVALID_PARAM;
379     }
380     char **certificateChain = NULL;
381     char *privKey = NULL;
382     size_t certChainLen = 0;
383     if (OC_STACK_OK != GenerateCertificateAndKeys(deviceId, &certificateChain,
384             &certChainLen, &privKey))
385     {
386         OIC_LOG(ERROR, TAG, "Error while generating credential data.");
387         return OC_STACK_ERROR;
388     }
389
390     uint8_t *publicJWK = NULL;
391     size_t len = 0;
392     if (OC_STACK_OK == CreateCertificatePublicJWK(certificateChain, certChainLen, &publicJWK, &len))
393     {
394
395     }
396     uint8_t *privateJWK = NULL;
397     size_t len1 = 0;
398     if (OC_STACK_OK == CreateCertificatePrivateJWK(privKey, &privateJWK, &len1))
399     {
400
401     }
402     for (size_t i = 0; i < certChainLen; ++i)
403     {
404         OICFree(certificateChain[i]);
405     }
406     OICFree(certificateChain);
407     OICFree(privKey);
408     if (NULL == publicJWK || NULL == privateJWK)
409     {
410         OICFree(publicJWK);
411         OICFree(privateJWK);
412         OIC_LOG(ERROR, TAG, "Error while converting keys to JWK format.");
413         return OC_STACK_ERROR;
414     }
415
416     OicSecCred_t *tempCred =  GenerateCredential(deviceId, SIGNED_ASYMMETRIC_KEY, publicJWK,
417                               privateJWK, 1, ptDeviceId);
418     OICFree(publicJWK);
419     OICFree(privateJWK);
420     if (NULL == tempCred)
421     {
422         OIC_LOG(ERROR, TAG, "Error while generating credential.");
423         return OC_STACK_ERROR;
424     }
425     *cred = tempCred;
426     return OC_STACK_OK;
427 }
428 #endif // __WITH_X509__