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"
22 #include "oic_malloc.h"
23 #include "oic_string.h"
25 #include "credresource.h"
29 #include "securevirtualresourcetypes.h"
31 #include "ck_manager.h"
33 #define CHAIN_LEN (2) //TODO: replace by external define or a runtime value
34 #endif //__WITH_X509__
36 #define TAG "SRPAPI-CG"
39 * @def PM_VERIFY_SUCCESS
40 * @brief Macro to verify success of operation.
41 * eg: PM_VERIFY_SUCCESS(TAG, OC_STACK_OK == foo(), OC_STACK_ERROR, ERROR);
42 * @note Invoking function must define "bail:" label for goto functionality to work correctly and
43 * must define "OCStackResult res" for setting error code.
45 #define PM_VERIFY_SUCCESS(tag, op, errCode, logLevel) { if (!(op)) \
46 {OIC_LOG((logLevel), tag, #op " failed!!"); res = errCode; goto bail;} }
48 * @def PM_VERIFY_NON_NULL
49 * @brief Macro to verify argument is not equal to NULL.
50 * eg: PM_VERIFY_NON_NULL(TAG, ptrData, ERROR);
51 * @note Invoking function must define "bail:" label for goto functionality to work correctly.
53 #define PM_VERIFY_NON_NULL(tag, arg, errCode, logLevel) { if (NULL == (arg)) \
54 { OIC_LOG((logLevel), tag, #arg " is NULL"); res = errCode; goto bail;} }
56 OCStackResult PMGeneratePairWiseCredentials(OicSecCredType_t type, size_t keySize,
57 const OicUuid_t *ptDeviceId,
58 const OicUuid_t *firstDeviceId, const OicUuid_t *secondDeviceId,
59 OicSecCred_t **firstCred, OicSecCred_t **secondCred)
62 if (NULL == ptDeviceId || NULL == firstDeviceId || NULL != *firstCred || \
63 NULL == secondDeviceId || NULL != *secondCred)
65 OIC_LOG(INFO, TAG, "Invalid params");
66 return OC_STACK_INVALID_PARAM;
68 if(!(keySize == OWNER_PSK_LENGTH_128 || keySize == OWNER_PSK_LENGTH_256))
70 OIC_LOG(INFO, TAG, "Invalid key size");
71 return OC_STACK_INVALID_PARAM;
73 OCStackResult res = OC_STACK_ERROR;
74 uint8_t* privData = NULL;
75 char* base64Buff = NULL;
76 OicSecCred_t *tempFirstCred = NULL;
77 OicSecCred_t *tempSecondCred = NULL;
79 size_t privDataKeySize = keySize;
81 privData = (uint8_t*) OICCalloc(privDataKeySize,sizeof(uint8_t));
82 PM_VERIFY_NON_NULL(TAG, privData, OC_STACK_NO_MEMORY, ERROR);
84 OCFillRandomMem(privData,privDataKeySize);
88 base64Buff = (char*) OICCalloc(B64ENCODE_OUT_SAFESIZE(privDataKeySize) + 1, sizeof(char));
89 PM_VERIFY_NON_NULL(TAG, base64Buff, OC_STACK_NO_MEMORY, ERROR);
90 int memReq = (B64ENCODE_OUT_SAFESIZE(privDataKeySize) + 1) * sizeof(char);
91 B64Result b64Ret = b64Encode(privData, privDataKeySize*sizeof(uint8_t), base64Buff,
93 PM_VERIFY_SUCCESS(TAG, B64_OK == b64Ret, OC_STACK_ERROR, ERROR);
95 // TODO: currently owner array is 1. only provisioning tool's id.
96 tempFirstCred = GenerateCredential(secondDeviceId, type, NULL, base64Buff, 1, ptDeviceId);
97 PM_VERIFY_NON_NULL(TAG, tempFirstCred, OC_STACK_ERROR, ERROR);
99 // TODO: currently owner array is 1. only provisioning tool's id.
100 tempSecondCred = GenerateCredential(firstDeviceId, type, NULL, base64Buff, 1, ptDeviceId);
101 PM_VERIFY_NON_NULL(TAG, tempSecondCred, OC_STACK_ERROR, ERROR);
103 *firstCred = tempFirstCred;
104 *secondCred = tempSecondCred;
111 if(res != OC_STACK_OK)
113 OICFree(tempFirstCred);
114 OICFree(tempSecondCred);
124 * Function to compose JSON Web Key (JWK) string from a certificate and a public key.
126 * @param[in] certificateChain Array of Base64 encoded certificate strings.
127 * @param[in] chainLength Number of the certificates in certificateChain.
128 * @return Valid JWK string on success, or NULL on fail.
130 static char *CreateCertificatePublicJWK(const char *const *certificateChain,
131 const size_t chainLength)
133 if (NULL == certificateChain || chainLength == 0)
135 OIC_LOG(ERROR, TAG, "Error CreateCertificatePublicJWK: Invalid params");
139 size_t certChainSize = 0;
140 for (size_t i = 0; i < chainLength; ++i)
142 if (NULL != certificateChain[i])
144 certChainSize += strlen(certificateChain[i]);
148 OIC_LOG(ERROR, TAG, "Error CreateCertificatePublicJWK: Invalid params");
153 /* certificates in the json array taken in quotes and separated by a comma
154 * so we have to count the number of characters (number of commas and quotes) required
155 * for embedding certificates in the array depending on the number of certificates in chain
156 * each certificate except last embeded in "\"%s\"," */
157 const int numCommasAndQuotes = chainLength * 3 - 1;
158 const char firstPart[] = "{\"kty\":\"EC\",\"crv\":\"P-256\",\"x5c\":[";
159 const char secondPart[] = "]}";
160 /* to calculate the size of JWK public part we need to add the value of first and second parts,
161 * size of certificate chain, number of additional commas and quotes and 1 for string termination symbol */
162 size_t certPubJWKLen = strlen(firstPart) + strlen(secondPart)
163 + certChainSize + numCommasAndQuotes + 1;
164 char *certPubJWK = (char *)OICMalloc(certPubJWKLen);
166 if (NULL != certPubJWK)
168 OICStrcpy(certPubJWK, certPubJWKLen, firstPart);
169 size_t offset = strlen(firstPart);
170 for (size_t i = 0; i < chainLength; ++i)
172 offset += sprintf(certPubJWK + offset, "\"%s\",", certificateChain[i]);
174 sprintf(certPubJWK + offset - 1, secondPart);
178 OIC_LOG(ERROR, TAG, "Error while memory allocation");
184 * Function to compose JWK string from a private key.
186 * @param[in] privateKey Base64 encoded private key.
187 * @return Valid JWK string on success, or NULL on fail.
189 static char *CreateCertificatePrivateJWK(const char *privateKey)
191 if (NULL == privateKey)
193 OIC_LOG(ERROR, TAG, "Error privateKey is NULL");
196 const char firstPart[] = "{\"kty\":\"EC\",\"crv\":\"P-256\",\"d\":\"";
197 const char secondPart[] = "\"}";
198 char *certPrivJWK = (char *)OICMalloc(strlen(firstPart) + strlen(secondPart) + strlen(
201 if (NULL != certPrivJWK)
203 sprintf(certPrivJWK, "%s%s%s", firstPart, privateKey, secondPart);
207 OIC_LOG(ERROR, TAG, "Error while memory allocation");
214 * Function to generate Base64 encoded credential data for device.
216 * @param[in] subject Device id.
217 * @param[out] certificateChain Pointer to Array of Base64 encoded certificate strings.
218 * @param[out] chainLength Pointer to number of the certificates in certificateChain.
219 * @param[out] privKey Pointer to Base64 encoded private key.
220 * @return OC_STACK_OK on success
222 static OCStackResult GenerateCertificateAndKeys(const OicUuid_t * subject, char *** const certificateChain,
223 size_t * const chainLength, char ** const privKey)
225 if (NULL == subject || NULL == certificateChain || NULL == chainLength || NULL == privKey)
227 return OC_STACK_INVALID_PARAM;
229 *certificateChain = NULL;
232 ByteArray pubKeyBA = BYTE_ARRAY_INITIALIZER;
233 ByteArray privKeyBA = BYTE_ARRAY_INITIALIZER;
234 ByteArray cert[CHAIN_LEN];
236 uint8_t pubKeyData[PUBLIC_KEY_SIZE] = {0};
237 uint8_t privKeyData[PRIVATE_KEY_SIZE] = {0};
238 uint8_t certData[ISSUER_MAX_CERT_SIZE * CHAIN_LEN] = {0};
239 uint8_t subjName[UUID_LENGTH + 1] = {0};
241 pubKeyBA.data = pubKeyData;
242 pubKeyBA.len = PUBLIC_KEY_SIZE;
243 privKeyBA.data = privKeyData;
244 privKeyBA.len = PRIVATE_KEY_SIZE;
245 for (size_t i = 0; i < CHAIN_LEN; ++i)
247 cert[i].data = certData + ISSUER_MAX_CERT_SIZE * i;
248 cert[i].len = ISSUER_MAX_CERT_SIZE;
251 memcpy(subjName, subject->id, UUID_LENGTH);
252 subjName[UUID_LENGTH] = '\0';
254 if (PKI_SUCCESS != GenerateKeyPair(&privKeyBA, &pubKeyBA))
256 OIC_LOG(ERROR, TAG, "Error generating keys.");
257 return OC_STACK_ERROR;
259 if (PKI_SUCCESS != CKMIssueDeviceCertificate(subjName, NULL, NULL, pubKeyBA.data, cert))
261 OIC_LOG(ERROR, TAG, "Error generating certificate.");
262 return OC_STACK_ERROR;
265 char privB64buf[B64ENCODE_OUT_SAFESIZE(PRIVATE_KEY_SIZE) + 1] = {0};
266 uint32_t privB64len = 0;
267 if (B64_OK != b64Encode(privKeyBA.data, privKeyBA.len, privB64buf,
268 B64ENCODE_OUT_SAFESIZE(PRIVATE_KEY_SIZE) + 1, &privB64len))
270 OIC_LOG(ERROR, TAG, "Error while encoding key");
271 return OC_STACK_ERROR;
274 if (PKI_SUCCESS != GetCAChain(chainLength , cert + 1))
276 OIC_LOG(ERROR, TAG, "Error getting CA certificate chain.");
277 return OC_STACK_ERROR;
281 *certificateChain = (char **)OICMalloc(sizeof(char *) * (*chainLength));
283 OCStackResult ret = OC_STACK_NO_MEMORY;
284 if (NULL == *certificateChain)
290 for (size_t i = 0; i < *chainLength; ++i)
292 (*certificateChain)[i] = NULL;
294 char certB64buf[B64ENCODE_OUT_SAFESIZE(ISSUER_MAX_CERT_SIZE) + 1] = {0};
295 uint32_t certB64len = 0;
296 if (B64_OK != b64Encode(cert[i].data, cert[i].len, certB64buf,
297 B64ENCODE_OUT_SAFESIZE(ISSUER_MAX_CERT_SIZE) + 1, &certB64len))
299 OIC_LOG(ERROR, TAG, "Error while encoding certificate");
300 ret = OC_STACK_ERROR;
304 (*certificateChain)[i] = (char *) OICMalloc(certB64len + 1);
305 if (NULL == (*certificateChain)[i])
310 memcpy((*certificateChain)[i], certB64buf, certB64len + 1);
314 *privKey = (char *)OICMalloc(privB64len + 1);
316 if (NULL == *privKey)
319 if (NULL != *certificateChain)
321 for (size_t i = 0; i < *chainLength; ++i)
323 OICFree((*certificateChain)[i]);
326 OICFree(*certificateChain);
327 *certificateChain = NULL;
330 if (OC_STACK_NO_MEMORY == ret)
332 OIC_LOG(ERROR, TAG, "Error while memory allocation");
337 memcpy(*privKey, privB64buf, privB64len + 1);
343 OCStackResult PMGenerateCertificateCredentials(const OicUuid_t *ptDeviceId,
344 const OicUuid_t *deviceId, OicSecCred_t **const cred)
346 if (NULL == ptDeviceId || NULL == deviceId || NULL == cred)
348 return OC_STACK_INVALID_PARAM;
350 char **certificateChain = NULL;
351 char *privKey = NULL;
352 size_t certChainLen = 0;
353 if (OC_STACK_OK != GenerateCertificateAndKeys(deviceId, &certificateChain,
354 &certChainLen, &privKey))
356 OIC_LOG(ERROR, TAG, "Error while generating credential data.");
357 return OC_STACK_ERROR;
360 char *publicJWK = CreateCertificatePublicJWK(certificateChain, certChainLen);
361 char *privateJWK = CreateCertificatePrivateJWK(privKey);
362 for (size_t i = 0; i < certChainLen; ++i)
364 OICFree(certificateChain[i]);
366 OICFree(certificateChain);
368 if (NULL == publicJWK || NULL == privateJWK)
372 OIC_LOG(ERROR, TAG, "Error while converting keys to JWK format.");
373 return OC_STACK_ERROR;
376 OicSecCred_t *tempCred = GenerateCredential(deviceId, SIGNED_ASYMMETRIC_KEY, publicJWK,
377 privateJWK, 1, ptDeviceId);
380 if (NULL == tempCred)
382 OIC_LOG(ERROR, TAG, "Error while generating credential.");
383 return OC_STACK_ERROR;
388 #endif // __WITH_X509__