1 /* *****************************************************************
3 * Copyright 2016 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 * *****************************************************************/
25 #include "oic_malloc.h"
26 #include "oic_string.h"
27 #include "cacommonutil.h"
29 #include "ocpayload.h"
30 #include "payload_logging.h"
31 #include "doxmresource.h"
32 #include "pmutility.h"
33 #include "secureresourceprovider.h"
35 // headers required for mbed TLS
36 #include "mbedtls/platform.h"
37 #include "mbedtls/ssl.h"
38 #include "mbedtls/entropy.h"
39 #include "mbedtls/ctr_drbg.h"
40 #include "mbedtls/pkcs12.h"
41 #include "mbedtls/ssl_internal.h"
42 #include "mbedtls/x509_csr.h"
45 #include "mbedtls/debug.h"
46 #include "mbedtls/version.h"
52 #define TAG "OIC_CLOUD_CSR"
54 //TODO: is it required in CSR response?
55 static OCByteString g_privateKey = {0, 0};
57 #define MAX_URI_QUERY MAX_URI_LENGTH + MAX_QUERY_LENGTH
59 #define MAX_STRING_LEN 254
63 * @brief Seed for initialization RNG
66 #define SEED "IOTIVITY_RND"
78 * Make CSR subject like:
79 * Subject: C=KR, O=Samsung, OU=OCF Device, CN=uuid:1234567890
80 * @param[in] subj the subject
82 static void CSRMakeSubject(char *subject, const char *countryCode, const char *organisation,
83 const char *organizationalUnitName, const char *deviceId)
85 OIC_LOG_V(DEBUG, TAG, "IN: %s", __func__);
89 OIC_LOG_V(ERROR, TAG, "%s: The device id is NULL",__func__);
92 snprintf(subject, MAX_STRING_LEN, "C=%s, O=%s, OU=%s, CN=uuid:%s", countryCode, organisation, organizationalUnitName, deviceId);
94 OIC_LOG_V(DEBUG, TAG, "OUT: %s", __func__);
97 * Generates elliptic keypair.
99 * @param[out] pk mbedtls public key container
101 * @return 0 on success or -1 on error
103 static int ecdsaGenKeypair(mbedtls_pk_context * pk)
105 OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
106 mbedtls_entropy_context entropy;
107 mbedtls_ctr_drbg_context ctr_drbg;
109 VERIFY_NON_NULL_RET(pk, TAG, "Param pk is NULL", -1);
113 unsigned char seed[sizeof(SEED)] = {0};
115 urandomFd = open("/dev/urandom", O_RDONLY);
118 OIC_LOG(ERROR, TAG, "Fails open /dev/urandom!");
119 OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
122 if(0 > read(urandomFd, seed, sizeof(seed)))
124 OIC_LOG(ERROR, TAG, "Fails read from /dev/urandom!");
126 OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
132 unsigned char * seed = (unsigned char*) SEED;
134 // Initialize and seed DRBG context
135 mbedtls_ctr_drbg_init(&ctr_drbg);
136 mbedtls_entropy_init(&entropy);
137 if (0 != mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func,
138 &entropy, seed, sizeof(SEED)))
140 OIC_LOG(ERROR, TAG, "Seed initialization failed!");
141 OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
144 mbedtls_ctr_drbg_set_prediction_resistance(&ctr_drbg, MBEDTLS_CTR_DRBG_PR_OFF);
145 // Initialize l context
147 if (0 > mbedtls_pk_setup(pk, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY)))
149 OIC_LOG(ERROR, TAG, "mbedtls_pk_info_from_type error");
150 OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
153 if (0 > mbedtls_ecp_group_load(&mbedtls_pk_ec(*pk)->grp, MBEDTLS_ECP_DP_SECP256R1))
155 OIC_LOG(ERROR, TAG, "mbedtls_ecp_group_load error");
156 OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
159 if (0 > mbedtls_ecp_gen_keypair(&mbedtls_pk_ec(*pk)->grp,
160 &mbedtls_pk_ec(*pk)->d,
161 &mbedtls_pk_ec(*pk)->Q,
162 mbedtls_ctr_drbg_random, &ctr_drbg))
164 OIC_LOG(ERROR, TAG, "mbedtls_ecp_gen_keypair error");
165 OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
169 OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
176 * Generates keypair and certificate signing request.
178 * @param[in] subjectName CSR Subject names should contain
179 * a comma-separated list of OID types and values:
180 * e.g. "C=UA,O=ABC,CN=uuid:32323232-3232-3232-3232-323232323232"
181 * @param[out] prKey private key in DER
182 * @param[out] prKeyLen private key buffer length
183 * @param[out] pubKey public key in DER
184 * @param[out] pubKeyLen public key buffer length
185 * @param[out] CSR certificate signing request in DER
186 * @param[out] CSRLen certificate signing request buffer length
188 * @return 0 on success or -1 on error
190 static int GenerateCSR(char *subject, OCByteString *csr)
192 OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
193 VERIFY_NON_NULL_RET(subject, TAG, "Param subject is NULL", -1);
194 VERIFY_NON_NULL_RET(csr, TAG, "Param csr is NULL", -1);
198 unsigned char * buf = NULL;
199 mbedtls_entropy_context entropy;
200 mbedtls_ctr_drbg_context ctr_drbg;
201 mbedtls_pk_context * key = NULL;
202 mbedtls_x509write_csr req;
204 // Initialize keypair context
205 key = (mbedtls_pk_context *)OICMalloc(sizeof(mbedtls_pk_context));
208 OIC_LOG_V(ERROR, TAG, "OICMalloc returned NULL on key allocation");
209 OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
213 if (0 > ecdsaGenKeypair(key))
215 OIC_LOG(ERROR, TAG, "ecdsaGenKeypair error");
216 OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
221 // Initialize CSR context
222 mbedtls_x509write_csr_init(&req);
223 // Set up MD algorithm, key and subject to CSR
224 mbedtls_x509write_csr_set_md_alg(&req, MBEDTLS_MD_SHA256);
225 mbedtls_x509write_csr_set_key(&req, key);
226 if (0 > mbedtls_x509write_csr_set_subject_name(&req, subject))
228 OIC_LOG(ERROR, TAG, "mbedtls_x509write_csr_set_subject_name error");
229 OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
235 unsigned char seed[sizeof(SEED)] = {0};
237 urandomFd = open("/dev/urandom", O_RDONLY);
240 OIC_LOG(ERROR, TAG, "Fails open /dev/urandom!");
241 OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
244 if(0 > read(urandomFd, seed, sizeof(seed)))
246 OIC_LOG(ERROR, TAG, "Fails read from /dev/urandom!");
248 OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
254 unsigned char * seed = (unsigned char *) SEED;
256 // Initialize and seed DRBG context
257 mbedtls_ctr_drbg_init(&ctr_drbg);
258 mbedtls_entropy_init(&entropy);
259 if (0 != mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func,
260 &entropy, seed, sizeof(SEED)))
262 OIC_LOG(ERROR, TAG, "Seed initialization failed!");
263 OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
266 mbedtls_ctr_drbg_set_prediction_resistance(&ctr_drbg, MBEDTLS_CTR_DRBG_PR_OFF);
269 buf = (unsigned char *)OICMalloc(bufsize * sizeof(unsigned char));
272 OIC_LOG(ERROR, TAG, "OICMalloc returned NULL on buf allocation");
273 OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
276 ret = mbedtls_x509write_csr_der(&req, buf, bufsize,
277 mbedtls_ctr_drbg_random, &ctr_drbg);
280 OIC_LOG(ERROR, TAG, "mbedtls_x509write_csr_der error");
281 OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
287 csr->bytes = (uint8_t *)OICMalloc(ret * sizeof(uint8_t));
288 if (NULL == csr->bytes)
290 OIC_LOG(ERROR, TAG, "OICMalloc returned NULL on csr allocation");
291 OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
294 memcpy(csr->bytes, buf + bufsize - ret, ret * sizeof(uint8_t));
296 // Private key to output
297 ret = mbedtls_pk_write_key_der(key, buf, bufsize);
300 OIC_LOG(ERROR, TAG, "mbedtls_pk_write_key_der error");
301 OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
304 g_privateKey.bytes = (uint8_t *)OICMalloc(ret * sizeof(char));
305 if (NULL == g_privateKey.bytes)
307 OIC_LOG(ERROR, TAG, "OICMalloc returned NULL on g_privateKey.bytes allocation");
308 OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
311 memcpy(g_privateKey.bytes, buf + bufsize - ret, ret * sizeof(uint8_t));
312 g_privateKey.len = ret;
313 // Public key to output
314 ret = mbedtls_pk_write_pubkey_der(key, buf, bufsize);
317 OIC_LOG(ERROR, TAG, "mbedtls_pk_write_pubkey_der error");
318 OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
321 //leave this, may be public key will be required in future
322 OCByteString publicKey;
323 publicKey.bytes = (uint8_t *)OICMalloc(ret * sizeof(char));
324 if (NULL == publicKey.bytes)
326 OIC_LOG(ERROR, TAG, "OICMalloc returned NULL on pubKey allocation");
327 OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
330 memcpy(publicKey.bytes, buf + bufsize - ret, ret * sizeof(uint8_t));
332 OICFree(publicKey.bytes);
334 mbedtls_entropy_free(&entropy);
335 mbedtls_ctr_drbg_free(&ctr_drbg);
336 mbedtls_x509write_csr_free(&req);
339 OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
344 * Cloud CSR Sign response handler
346 * @param[in] ctx context
347 * @param[out] data data required to external application
348 * @param[in] response peer response
349 * @return OCStackResult application result
351 static OCStackResult HandleCertificateIssueRequest(void *ctx, void **data, OCClientResponse *response)
353 OCStackResult result = OC_STACK_OK;
354 OIC_LOG_V(DEBUG, TAG, "IN: %s", __func__);
361 OIC_LOG_V(ERROR, TAG, "%s: Client response is null",__func__);
362 return OC_STACK_INVALID_PARAM;
365 if (response->result < 4 && response->payload)
367 OIC_LOG_V(ERROR, TAG, "CSR sign error: result: %d, payload null: %s",
368 response->result, response->payload ? "no" : "yes");
369 OIC_LOG_PAYLOAD(DEBUG, response->payload);
370 return OC_STACK_ERROR;
375 if (!OCRepPayloadGetPropString((OCRepPayload *)response->payload,
376 OC_RSRVD_DEVICE_ID, &deviceId))
378 OIC_LOG(ERROR, TAG, "Can't get: Device Id");
379 result = OC_STACK_ERROR;
383 if (!OCRepPayloadGetPropPubDataType((OCRepPayload *)response->payload,
384 OC_RSRVD_CERT, &cert))
386 OIC_LOG_V(ERROR, TAG, "Can't get: %s", OC_RSRVD_CERT);
387 result = OC_STACK_ERROR;
399 result = SRPSaveOwnCertChain(&cert, &key, &credId);
400 if (result != OC_STACK_OK)
402 OIC_LOG(ERROR, TAG, "Can't add cert");
408 if (!OCRepPayloadGetPropPubDataType((OCRepPayload *)response->payload,
409 OC_RSRVD_CACERT, &caCert))
411 OIC_LOG_V(ERROR, TAG, "Can't get: %s", OC_RSRVD_CACERT);
412 result = OC_STACK_ERROR;
417 result = SRPSaveTrustCertChain(caCert.data, caCert.len, caCert.encoding, &credId);
418 if (result != OC_STACK_OK)
420 OIC_LOG(ERROR, TAG, "Can't insert CA cert");
426 OICClearMemory(g_privateKey.bytes, g_privateKey.len);
427 OICFree(g_privateKey.bytes);
428 g_privateKey.bytes = NULL;
429 g_privateKey.len = 0;
431 OIC_LOG_V(DEBUG, TAG, "OUT: %s", __func__);
437 * Certificate-Issue request function
439 * @param[in] endPoint cloud host and port
440 * @return OCStackResult application result
442 OCStackResult OCCloudCertificateIssueRequest(void* ctx,
443 const OCDevAddr *endPoint,
444 OCCloudResponseCB callback)
446 OCStackResult ret = OC_STACK_OK;
448 OIC_LOG_V(DEBUG, TAG, "IN: %s", __func__);
450 if (NULL == endPoint)
452 OIC_LOG(ERROR, TAG, "Input parameter endpoint is NULL");
453 return OC_STACK_INVALID_PARAM;
456 char *deviceId = getDeviceId();
458 char subject[MAX_STRING_LEN] = { 0 };
459 CSRMakeSubject(subject, "KR", "Samsung", "OCF Device", deviceId);
461 OIC_LOG_V(DEBUG, TAG, "Certificate Request subject: %s", subject);
463 OCByteString request = {0};
464 if (0 != GenerateCSR(subject, &request))
466 OIC_LOG(ERROR, TAG, "Cann't get the sertificate request");
467 ret = OC_STACK_ERROR;
470 OIC_LOG(DEBUG, TAG, "Certificate Request:");
471 OIC_LOG_BUFFER(DEBUG, TAG, request.bytes, request.len);
473 OIC_LOG(DEBUG, TAG, "Private Key:");
474 OIC_LOG_BUFFER(DEBUG, TAG, g_privateKey.bytes, g_privateKey.len);
476 OCRepPayload* payload = OCRepPayloadCreate();
479 OIC_LOG(ERROR, TAG, "Failed to memory allocation");
480 ret = OC_STACK_ERROR;
484 OCRepPayloadSetPropString(payload, OC_RSRVD_DEVICE_ID, deviceId);
486 OicSecKey_t csr = {.data = request.bytes, .len = request.len, .encoding = OIC_ENCODING_DER};
488 OCRepPayloadSetPropPubDataType(payload, OC_RSRVD_CSR, &csr);
490 OIC_LOG_PAYLOAD(DEBUG, (OCPayload *)payload);
492 char uri[MAX_URI_QUERY] = { 0 };
493 snprintf(uri, MAX_URI_QUERY, DEFAULT_QUERY,
494 endPoint->addr, endPoint->port,
495 OC_RSRVD_PROV_CERT_URI);
496 OIC_LOG_V(DEBUG, TAG, "Certificate Request Query: %s", uri);
498 OCCallbackData cbData;
499 fillCallbackData(&cbData, ctx, callback, HandleCertificateIssueRequest, NULL);
501 ret = OCDoResource(NULL, OC_REST_POST, uri, NULL,
502 (OCPayload *)payload,
504 OC_LOW_QOS, &cbData, NULL, 0);
506 OIC_LOG_V(DEBUG, TAG, "OUT: %s", __func__);
508 OICFree(request.bytes);