1 /* *****************************************************************
3 * Copyright 2015 Samsung Electronics All Rights Reserved.
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 * *****************************************************************/
21 #include "credentialgenerator.h"
23 #include "oic_malloc.h"
24 #include "oic_string.h"
25 #include "ocpayload.h"
26 #include "payload_logging.h"
27 #include "credresource.h"
29 #include "srmutility.h"
31 #include "securevirtualresourcetypes.h"
33 #include "ck_manager.h"
35 #define CHAIN_LEN (2) //TODO: replace by external define or a runtime value
36 #endif //__WITH_X509__
38 #define TAG "SRPAPI-CG"
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;
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)
52 if (NULL == ptDeviceId || NULL == firstDeviceId || NULL != *firstCred || \
53 NULL == secondDeviceId || NULL != *secondCred)
55 OIC_LOG(INFO, TAG, "Invalid params");
56 return OC_STACK_INVALID_PARAM;
58 if(!(keySize == OWNER_PSK_LENGTH_128 || keySize == OWNER_PSK_LENGTH_256))
60 OIC_LOG(INFO, TAG, "Invalid key size");
61 return OC_STACK_INVALID_PARAM;
63 OCStackResult res = OC_STACK_ERROR;
64 OicSecCred_t *tempFirstCred = NULL;
65 OicSecCred_t *tempSecondCred = NULL;
67 size_t privDataKeySize = keySize;
69 uint8_t *privData = (uint8_t *)OICCalloc(privDataKeySize, sizeof(uint8_t));
70 VERIFY_NON_NULL(TAG, privData, ERROR);
72 OCFillRandomMem(privData, privDataKeySize);
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);
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);
82 *firstCred = tempFirstCred;
83 *secondCred = tempSecondCred;
89 if(res != OC_STACK_OK)
91 OICFree(tempFirstCred);
92 OICFree(tempSecondCred);
102 * Function to compose JSON Web Key (JWK) string from a certificate and a public key.
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.
109 static OCStackResult CreateCertificatePublicJWK(const char *const *certificateChain,
110 const size_t chainLength, uint8_t **cborPayload, size_t *size)
112 OCStackResult ret = OC_STACK_ERROR;
116 if (NULL == certificateChain || chainLength == 0)
118 OIC_LOG(ERROR, TAG, "Error CreateCertificatePublicJWK: Invalid params");
119 return OC_STACK_INVALID_PARAM;
122 size_t certChainSize = 0;
123 for (size_t i = 0; i < chainLength; ++i)
125 if (NULL != certificateChain[i])
127 certChainSize += strlen(certificateChain[i]);
131 OIC_LOG(ERROR, TAG, "Error CreateCertificatePublicJWK: Invalid params");
132 return OC_STACK_INVALID_PARAM;
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);
145 CborEncoder credMap = { .end = 0 };
146 cborEncoderResult |= cbor_encoder_create_map(&encoder, &credMap, CertMapSize);
147 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Cred Map.");
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 ");
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 ");
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++)
169 cborEncoderResult |= cbor_encode_byte_string(&certs, (uint8_t *)certificateChain[i], strlen(certificateChain[i]));
170 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Certificate Chain.");
172 cborEncoderResult |= cbor_encoder_close_container(&credMap, &certs);
173 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing Certificate Chain.");
175 cborEncoderResult |= cbor_encoder_close_container(&encoder, &credMap);
176 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing Cred Map.");
178 *cborPayload = outPayload;
179 *size = encoder.ptr - outPayload;
187 * Function to compose JWK string from a private key.
189 * @param privateKey to be converted to CBOR.
190 * @ Valid JWK string on success, or NULL on fail.
192 OCStackResult CreateCertificatePrivateJWK(const char *privateKey, uint8_t **cborPayload,
197 OCStackResult ret = OC_STACK_INVALID_PARAM;
198 VERIFY_NON_NULL(TAG, privateKey, ERROR);
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);
208 CborEncoder encoder = { .end = 0 };
209 cbor_encoder_init(&encoder, outPayload, cborLen, 0);
211 CborEncoder credMap = { .end = 0 };
212 cborEncoderResult |= cbor_encoder_create_map(&encoder, &credMap, 3);
213 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding ");
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 ");
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 ");
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.");
233 cborEncoderResult |= cbor_encoder_close_container(&encoder, &credMap);
234 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing Cred Map.");
236 *cborPayload = outPayload;
237 *size = encoder.ptr - outPayload;
245 * Function to generate Base64 encoded credential data for device.
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
253 static OCStackResult GenerateCertificateAndKeys(const OicUuid_t * subject, char *** const certificateChain,
254 size_t * const chainLength, char ** const privKey)
256 if (NULL == subject || NULL == certificateChain || NULL == chainLength || NULL == privKey)
258 return OC_STACK_INVALID_PARAM;
260 *certificateChain = NULL;
263 ByteArray pubKeyBA = BYTE_ARRAY_INITIALIZER;
264 ByteArray privKeyBA = BYTE_ARRAY_INITIALIZER;
265 ByteArray cert[CHAIN_LEN];
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};
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)
278 cert[i].data = certData + ISSUER_MAX_CERT_SIZE * i;
279 cert[i].len = ISSUER_MAX_CERT_SIZE;
282 memcpy(subjName, subject->id, UUID_LENGTH);
283 subjName[UUID_LENGTH] = '\0';
285 if (PKI_SUCCESS != GenerateKeyPair(&privKeyBA, &pubKeyBA))
287 OIC_LOG(ERROR, TAG, "Error generating keys.");
288 return OC_STACK_ERROR;
290 if (PKI_SUCCESS != CKMIssueDeviceCertificate(subjName, NULL, NULL, pubKeyBA.data, cert))
292 OIC_LOG(ERROR, TAG, "Error generating certificate.");
293 return OC_STACK_ERROR;
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))
301 OIC_LOG(ERROR, TAG, "Error while encoding key");
302 return OC_STACK_ERROR;
305 if (PKI_SUCCESS != GetCAChain(chainLength , cert + 1))
307 OIC_LOG(ERROR, TAG, "Error getting CA certificate chain.");
308 return OC_STACK_ERROR;
312 *certificateChain = (char **)OICMalloc(sizeof(char *) * (*chainLength));
314 OCStackResult ret = OC_STACK_NO_MEMORY;
315 if (NULL == *certificateChain)
321 for (size_t i = 0; i < *chainLength; ++i)
323 (*certificateChain)[i] = NULL;
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))
330 OIC_LOG(ERROR, TAG, "Error while encoding certificate");
331 ret = OC_STACK_ERROR;
335 (*certificateChain)[i] = (char *) OICMalloc(certB64len + 1);
336 if (NULL == (*certificateChain)[i])
341 memcpy((*certificateChain)[i], certB64buf, certB64len + 1);
345 *privKey = (char *)OICMalloc(privB64len + 1);
347 if (NULL == *privKey)
350 if (NULL != *certificateChain)
352 for (size_t i = 0; i < *chainLength; ++i)
354 OICFree((*certificateChain)[i]);
357 OICFree(*certificateChain);
358 *certificateChain = NULL;
361 if (OC_STACK_NO_MEMORY == ret)
363 OIC_LOG(ERROR, TAG, "Error while memory allocation");
368 memcpy(*privKey, privB64buf, privB64len + 1);
373 OCStackResult PMGenerateCertificateCredentials(const OicUuid_t *ptDeviceId,
374 const OicUuid_t *deviceId, OicSecCred_t **const cred)
376 if (NULL == ptDeviceId || NULL == deviceId || NULL == cred)
378 return OC_STACK_INVALID_PARAM;
380 char **certificateChain = NULL;
381 char *privKey = NULL;
382 size_t certChainLen = 0;
383 if (OC_STACK_OK != GenerateCertificateAndKeys(deviceId, &certificateChain,
384 &certChainLen, &privKey))
386 OIC_LOG(ERROR, TAG, "Error while generating credential data.");
387 return OC_STACK_ERROR;
390 uint8_t *publicJWK = NULL;
392 if (OC_STACK_OK == CreateCertificatePublicJWK(certificateChain, certChainLen, &publicJWK, &len))
396 uint8_t *privateJWK = NULL;
398 if (OC_STACK_OK == CreateCertificatePrivateJWK(privKey, &privateJWK, &len1))
402 for (size_t i = 0; i < certChainLen; ++i)
404 OICFree(certificateChain[i]);
406 OICFree(certificateChain);
408 if (NULL == publicJWK || NULL == privateJWK)
412 OIC_LOG(ERROR, TAG, "Error while converting keys to JWK format.");
413 return OC_STACK_ERROR;
416 OicSecCred_t *tempCred = GenerateCredential(deviceId, SIGNED_ASYMMETRIC_KEY, publicJWK,
417 privateJWK, 1, ptDeviceId);
420 if (NULL == tempCred)
422 OIC_LOG(ERROR, TAG, "Error while generating credential.");
423 return OC_STACK_ERROR;
428 #endif // __WITH_X509__