3cb44fcd92dba8a0c175971aece4446cfa8aaf4b
[platform/upstream/iotivity.git] / resource / csdk / security / provisioning / src / cloud / csr.c
1 /* *****************************************************************
2  *
3  * Copyright 2016 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 "utils.h"
21
22 #include "logger.h"
23 #include <stddef.h>
24 #include <string.h>
25 #include "oic_malloc.h"
26 #include "oic_string.h"
27 #include "cacommonutil.h"
28
29 #include "ocpayload.h"
30 #include "payload_logging.h"
31 #include "doxmresource.h"
32 #include "pmutility.h"
33 #include "secureresourceprovider.h"
34
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"
43
44 #ifndef NDEBUG
45 #include "mbedtls/debug.h"
46 #include "mbedtls/version.h"
47 #endif
48
49 #include <unistd.h>
50 #include <fcntl.h>
51
52 #define TAG "OIC_CLOUD_CSR"
53
54 //TODO: is it required in CSR response?
55 static OCByteString g_privateKey = {0, 0};
56
57 #define MAX_URI_QUERY MAX_URI_LENGTH + MAX_QUERY_LENGTH
58
59 #define MAX_STRING_LEN 254
60
61 /**
62  * @def SEED
63  * @brief Seed for initialization RNG
64  */
65
66 #define SEED "IOTIVITY_RND"
67
68 typedef struct
69 {
70     char *subject;
71     char *prKey;
72     size_t prKeyLen;
73     char *pubKey;
74     size_t pubKeyLen;
75 } SignCred_t;
76
77 /**
78  * Make CSR subject like:
79  * Subject: C=KR, O=Samsung, OU=OCF Device, CN=uuid:1234567890
80  * @param[in] subj              the subject
81  */
82 static void CSRMakeSubject(char *subject, const char *countryCode, const char *organisation,
83                     const char *organizationalUnitName, const char *deviceId)
84 {
85     OIC_LOG_V(DEBUG, TAG, "IN: %s", __func__);
86
87     if (!deviceId)
88     {
89         OIC_LOG_V(ERROR, TAG, "%s: The device id is NULL",__func__);
90         return;
91     }
92     snprintf(subject, MAX_STRING_LEN, "C=%s, O=%s, OU=%s, CN=uuid:%s", countryCode, organisation, organizationalUnitName, deviceId);
93
94     OIC_LOG_V(DEBUG, TAG, "OUT: %s", __func__);
95 }
96 /**
97  * Generates elliptic keypair.
98  *
99  * @param[out]  pk    mbedtls public key container
100  *
101  * @return  0 on success or -1 on error
102  */
103 static int ecdsaGenKeypair(mbedtls_pk_context * pk)
104 {
105     OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
106     mbedtls_entropy_context entropy;
107     mbedtls_ctr_drbg_context ctr_drbg;
108
109     VERIFY_NON_NULL_RET(pk, TAG, "Param pk is NULL", -1);
110
111     // Entropy seeding
112 #ifdef __unix__
113     unsigned char seed[sizeof(SEED)] = {0};
114     int urandomFd = -2;
115     urandomFd = open("/dev/urandom", O_RDONLY);
116     if(urandomFd == -1)
117     {
118         OIC_LOG(ERROR, TAG, "Fails open /dev/urandom!");
119         OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
120         return -1;
121     }
122     if(0 > read(urandomFd, seed, sizeof(seed)))
123     {
124         OIC_LOG(ERROR, TAG, "Fails read from /dev/urandom!");
125         close(urandomFd);
126         OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
127         return -1;
128     }
129     close(urandomFd);
130
131 #else
132     unsigned char * seed = (unsigned char*) SEED;
133 #endif
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)))
139     {
140         OIC_LOG(ERROR, TAG, "Seed initialization failed!");
141         OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
142         return -1;
143     }
144     mbedtls_ctr_drbg_set_prediction_resistance(&ctr_drbg, MBEDTLS_CTR_DRBG_PR_OFF);
145     // Initialize l context
146     mbedtls_pk_init(pk);
147     if (0 > mbedtls_pk_setup(pk, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY)))
148     {
149         OIC_LOG(ERROR, TAG, "mbedtls_pk_info_from_type error");
150         OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
151         return -1;
152     }
153     if (0 > mbedtls_ecp_group_load(&mbedtls_pk_ec(*pk)->grp, MBEDTLS_ECP_DP_SECP256R1))
154     {
155         OIC_LOG(ERROR, TAG, "mbedtls_ecp_group_load error");
156         OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
157         return -1;
158     }
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))
163     {
164         OIC_LOG(ERROR, TAG, "mbedtls_ecp_gen_keypair error");
165         OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
166         return -1;
167     }
168
169     OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
170     return 0;
171 }
172
173
174
175 /**
176  * Generates keypair and certificate signing request.
177  *
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
187  *
188  * @return  0 on success or -1 on error
189  */
190 static int GenerateCSR(char *subject, OCByteString *csr)
191 {
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);
195
196     int ret = 0;
197     int bufsize = 1024;
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;
203
204     // Initialize keypair context
205     key = (mbedtls_pk_context *)OICMalloc(sizeof(mbedtls_pk_context));
206     if (NULL == key)
207     {
208         OIC_LOG_V(ERROR, TAG, "OICMalloc returned NULL on key allocation");
209         OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
210         return -1;
211     }
212     // Generate keypair
213     if (0 > ecdsaGenKeypair(key))
214     {
215         OIC_LOG(ERROR, TAG, "ecdsaGenKeypair error");
216         OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
217         OICFree(key);
218         return -1;
219     }
220
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))
227     {
228         OIC_LOG(ERROR, TAG, "mbedtls_x509write_csr_set_subject_name error");
229         OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
230         return -1;
231     }
232
233     // Entropy seeding
234 #ifdef __unix__
235     unsigned char seed[sizeof(SEED)] = {0};
236     int urandomFd = -2;
237     urandomFd = open("/dev/urandom", O_RDONLY);
238     if(urandomFd == -1)
239     {
240         OIC_LOG(ERROR, TAG, "Fails open /dev/urandom!");
241         OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
242         return -1;
243     }
244     if(0 > read(urandomFd, seed, sizeof(seed)))
245     {
246         OIC_LOG(ERROR, TAG, "Fails read from /dev/urandom!");
247         close(urandomFd);
248         OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
249         return -1;
250     }
251     close(urandomFd);
252
253 #else
254     unsigned char * seed = (unsigned char *) SEED;
255 #endif
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)))
261     {
262         OIC_LOG(ERROR, TAG, "Seed initialization failed!");
263         OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
264         return -1;
265     }
266     mbedtls_ctr_drbg_set_prediction_resistance(&ctr_drbg, MBEDTLS_CTR_DRBG_PR_OFF);
267
268     // Create CSR
269     buf = (unsigned char *)OICMalloc(bufsize * sizeof(unsigned char));
270     if (NULL == buf)
271     {
272         OIC_LOG(ERROR, TAG, "OICMalloc returned NULL on buf allocation");
273         OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
274         return -1;
275     }
276     ret = mbedtls_x509write_csr_der(&req, buf, bufsize,
277                                     mbedtls_ctr_drbg_random, &ctr_drbg);
278     if (ret < 0)
279     {
280         OIC_LOG(ERROR, TAG, "mbedtls_x509write_csr_der error");
281         OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
282         OICFree(buf);
283         return -1;
284     }
285
286     // CSR to output
287     csr->bytes = (uint8_t *)OICMalloc(ret * sizeof(uint8_t));
288     if (NULL == csr->bytes)
289     {
290         OIC_LOG(ERROR, TAG, "OICMalloc returned NULL on csr allocation");
291         OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
292         return -1;
293     }
294     memcpy(csr->bytes, buf + bufsize - ret, ret * sizeof(uint8_t));
295     csr->len = ret;
296     // Private key to output
297     ret = mbedtls_pk_write_key_der(key, buf, bufsize);
298     if (ret < 0)
299     {
300         OIC_LOG(ERROR, TAG, "mbedtls_pk_write_key_der error");
301         OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
302         return -1;
303     }
304     g_privateKey.bytes = (uint8_t *)OICMalloc(ret * sizeof(char));
305     if (NULL == g_privateKey.bytes)
306     {
307         OIC_LOG(ERROR, TAG, "OICMalloc returned NULL on g_privateKey.bytes allocation");
308         OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
309         return -1;
310     }
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);
315     if (ret < 0)
316     {
317         OIC_LOG(ERROR, TAG, "mbedtls_pk_write_pubkey_der error");
318         OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
319         return -1;
320     }
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)
325     {
326         OIC_LOG(ERROR, TAG, "OICMalloc returned NULL on pubKey allocation");
327         OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
328         return -1;
329     }
330     memcpy(publicKey.bytes, buf + bufsize - ret, ret * sizeof(uint8_t));
331     publicKey.len = ret;
332     OICFree(publicKey.bytes);
333
334     mbedtls_entropy_free(&entropy);
335     mbedtls_ctr_drbg_free(&ctr_drbg);
336     mbedtls_x509write_csr_free(&req);
337     OICFree(key);
338
339     OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
340     return 0;
341 }
342
343 /**
344  * Cloud CSR Sign response handler
345
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
350  */
351 static OCStackResult HandleCertificateIssueRequest(void *ctx, void **data, OCClientResponse *response)
352 {
353     OCStackResult result = OC_STACK_OK;
354     OIC_LOG_V(DEBUG, TAG, "IN: %s", __func__);
355
356     OC_UNUSED(ctx);
357     OC_UNUSED(data);
358
359     if (!response)
360     {
361         OIC_LOG_V(ERROR, TAG, "%s: Client response is null",__func__);
362         return OC_STACK_INVALID_PARAM;
363     }
364
365     if (response->result < 4 && response->payload)
366     {
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;
371     }
372
373     char *deviceId = 0;
374
375     if (!OCRepPayloadGetPropString((OCRepPayload *)response->payload,
376                                    OC_RSRVD_DEVICE_ID, &deviceId))
377     {
378         OIC_LOG(ERROR, TAG, "Can't get: Device Id");
379         result = OC_STACK_ERROR;
380     }
381
382     OicSecKey_t cert;
383     if (!OCRepPayloadGetPropPubDataType((OCRepPayload *)response->payload,
384                                    OC_RSRVD_CERT, &cert))
385     {
386         OIC_LOG_V(ERROR, TAG, "Can't get: %s", OC_RSRVD_CERT);
387         result = OC_STACK_ERROR;
388     }
389     else
390     {
391         OicSecKey_t key =
392         {
393             g_privateKey.bytes,
394             g_privateKey.len,
395             OIC_ENCODING_DER
396         };
397
398         uint16_t credId;
399         result = SRPSaveOwnCertChain(&cert, &key, &credId);
400         if (result != OC_STACK_OK)
401         {
402             OIC_LOG(ERROR, TAG, "Can't add cert");
403         }
404     }
405
406     //get cacert
407     OicSecKey_t caCert;
408     if (!OCRepPayloadGetPropPubDataType((OCRepPayload *)response->payload,
409                                    OC_RSRVD_CACERT, &caCert))
410     {
411         OIC_LOG_V(ERROR, TAG, "Can't get: %s", OC_RSRVD_CACERT);
412         result = OC_STACK_ERROR;
413     }
414     else
415     {
416         uint16_t credId;
417         result = SRPSaveTrustCertChain(caCert.data, caCert.len, caCert.encoding, &credId);
418         if (result != OC_STACK_OK)
419         {
420             OIC_LOG(ERROR, TAG, "Can't insert CA cert");
421         }
422     }
423
424     OICFree(deviceId);
425
426     OICClearMemory(g_privateKey.bytes, g_privateKey.len);
427     OICFree(g_privateKey.bytes);
428     g_privateKey.bytes = NULL;
429     g_privateKey.len   = 0;
430
431     OIC_LOG_V(DEBUG, TAG, "OUT: %s", __func__);
432
433     return result;
434 }
435
436 /**
437  * Certificate-Issue request function
438  *
439  * @param[in] endPoint          cloud host and port
440  * @return  OCStackResult application result
441  */
442 OCStackResult OCCloudCertificateIssueRequest(void* ctx,
443                                              const OCDevAddr *endPoint,
444                                              OCCloudResponseCB callback)
445 {
446     OCStackResult ret = OC_STACK_OK;
447
448     OIC_LOG_V(DEBUG, TAG, "IN: %s", __func__);
449
450     if (NULL == endPoint)
451     {
452         OIC_LOG(ERROR, TAG, "Input parameter endpoint is NULL");
453         return OC_STACK_INVALID_PARAM;
454     }
455
456     char *deviceId = getDeviceId();
457
458     char subject[MAX_STRING_LEN] = { 0 };
459     CSRMakeSubject(subject, "KR", "Samsung", "OCF Device", deviceId);
460
461     OIC_LOG_V(DEBUG, TAG, "Certificate Request subject: %s", subject);
462
463     OCByteString request = {0};
464     if (0 != GenerateCSR(subject, &request))
465     {
466         OIC_LOG(ERROR, TAG, "Cann't get the sertificate request");
467         ret = OC_STACK_ERROR;
468         goto exit;
469     }
470     OIC_LOG(DEBUG, TAG, "Certificate Request:");
471     OIC_LOG_BUFFER(DEBUG, TAG, request.bytes, request.len);
472
473     OIC_LOG(DEBUG, TAG, "Private Key:");
474     OIC_LOG_BUFFER(DEBUG, TAG, g_privateKey.bytes, g_privateKey.len);
475
476     OCRepPayload* payload = OCRepPayloadCreate();
477     if (!payload)
478     {
479         OIC_LOG(ERROR, TAG, "Failed to memory allocation");
480         ret = OC_STACK_ERROR;
481         goto exit;
482     }
483
484     OCRepPayloadSetPropString(payload, OC_RSRVD_DEVICE_ID, deviceId);
485
486     OicSecKey_t csr = {.data = request.bytes, .len = request.len, .encoding = OIC_ENCODING_DER};
487
488     OCRepPayloadSetPropPubDataType(payload, OC_RSRVD_CSR, &csr);
489
490     OIC_LOG_PAYLOAD(DEBUG, (OCPayload *)payload);
491
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);
497
498     OCCallbackData cbData;
499     fillCallbackData(&cbData, ctx, callback, HandleCertificateIssueRequest, NULL);
500
501     ret = OCDoResource(NULL, OC_REST_POST, uri, NULL,
502                        (OCPayload *)payload,
503                        CT_ADAPTER_TCP,
504                        OC_LOW_QOS, &cbData, NULL, 0);
505
506     OIC_LOG_V(DEBUG, TAG, "OUT: %s", __func__);
507 exit:
508     OICFree(request.bytes);
509     return ret;
510 }