replace : iotivity -> iotivity-sec
[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         return -1;
218     }
219
220     // Initialize CSR context
221     mbedtls_x509write_csr_init(&req);
222     // Set up MD algorithm, key and subject to CSR
223     mbedtls_x509write_csr_set_md_alg(&req, MBEDTLS_MD_SHA256);
224     mbedtls_x509write_csr_set_key(&req, key);
225     if (0 > mbedtls_x509write_csr_set_subject_name(&req, subject))
226     {
227         OIC_LOG(ERROR, TAG, "mbedtls_x509write_csr_set_subject_name error");
228         OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
229         return -1;
230     }
231
232     // Entropy seeding
233 #ifdef __unix__
234     unsigned char seed[sizeof(SEED)] = {0};
235     int urandomFd = -2;
236     urandomFd = open("/dev/urandom", O_RDONLY);
237     if(urandomFd == -1)
238     {
239         OIC_LOG(ERROR, TAG, "Fails open /dev/urandom!");
240         OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
241         return -1;
242     }
243     if(0 > read(urandomFd, seed, sizeof(seed)))
244     {
245         OIC_LOG(ERROR, TAG, "Fails read from /dev/urandom!");
246         close(urandomFd);
247         OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
248         return -1;
249     }
250     close(urandomFd);
251
252 #else
253     unsigned char * seed = (unsigned char *) SEED;
254 #endif
255     // Initialize and seed DRBG context
256     mbedtls_ctr_drbg_init(&ctr_drbg);
257     mbedtls_entropy_init(&entropy);
258     if (0 != mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func,
259                                    &entropy, seed, sizeof(SEED)))
260     {
261         OIC_LOG(ERROR, TAG, "Seed initialization failed!");
262         OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
263         return -1;
264     }
265     mbedtls_ctr_drbg_set_prediction_resistance(&ctr_drbg, MBEDTLS_CTR_DRBG_PR_OFF);
266
267     // Create CSR
268     buf = (unsigned char *)OICMalloc(bufsize * sizeof(unsigned char));
269     if (NULL == buf)
270     {
271         OIC_LOG(ERROR, TAG, "OICMalloc returned NULL on buf allocation");
272         OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
273         return -1;
274     }
275     ret = mbedtls_x509write_csr_der(&req, buf, bufsize,
276                                     mbedtls_ctr_drbg_random, &ctr_drbg);
277     if (ret < 0)
278     {
279         OIC_LOG(ERROR, TAG, "mbedtls_x509write_csr_der error");
280         OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
281         return -1;
282     }
283
284     // CSR to output
285     csr->bytes = (uint8_t *)OICMalloc(ret * sizeof(uint8_t));
286     if (NULL == csr->bytes)
287     {
288         OIC_LOG(ERROR, TAG, "OICMalloc returned NULL on csr allocation");
289         OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
290         return -1;
291     }
292     memcpy(csr->bytes, buf + bufsize - ret, ret * sizeof(uint8_t));
293     csr->len = ret;
294     // Private key to output
295     ret = mbedtls_pk_write_key_der(key, buf, bufsize);
296     if (ret < 0)
297     {
298         OIC_LOG(ERROR, TAG, "mbedtls_pk_write_key_der error");
299         OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
300         return -1;
301     }
302     g_privateKey.bytes = (uint8_t *)OICMalloc(ret * sizeof(char));
303     if (NULL == g_privateKey.bytes)
304     {
305         OIC_LOG(ERROR, TAG, "OICMalloc returned NULL on g_privateKey.bytes allocation");
306         OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
307         return -1;
308     }
309     memcpy(g_privateKey.bytes, buf + bufsize - ret, ret * sizeof(uint8_t));
310     g_privateKey.len = ret;
311     // Public key to output
312     ret = mbedtls_pk_write_pubkey_der(key, buf, bufsize);
313     if (ret < 0)
314     {
315         OIC_LOG(ERROR, TAG, "mbedtls_pk_write_pubkey_der error");
316         OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
317         return -1;
318     }
319     //leave this, may be public key will be required in future
320     OCByteString publicKey;
321     publicKey.bytes = (uint8_t *)OICMalloc(ret * sizeof(char));
322     if (NULL == publicKey.bytes)
323     {
324         OIC_LOG(ERROR, TAG, "OICMalloc returned NULL on pubKey allocation");
325         OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
326         return -1;
327     }
328     memcpy(publicKey.bytes, buf + bufsize - ret, ret * sizeof(uint8_t));
329     publicKey.len = ret;
330     OICFree(publicKey.bytes);
331
332     mbedtls_entropy_free(&entropy);
333     mbedtls_ctr_drbg_free(&ctr_drbg);
334     mbedtls_x509write_csr_free(&req);
335     OICFree(key);
336
337     OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
338     return 0;
339 }
340
341 /**
342  * Cloud CSR Sign response handler
343
344  * @param[in] ctx       context
345  * @param[out] data     data required to external application
346  * @param[in] response  peer response
347  * @return  OCStackResult application result
348  */
349 static OCStackResult HandleCertificateIssueRequest(void *ctx, void **data, OCClientResponse *response)
350 {
351     OCStackResult result = OC_STACK_OK;
352     OIC_LOG_V(DEBUG, TAG, "IN: %s", __func__);
353
354     OC_UNUSED(ctx);
355     OC_UNUSED(data);
356
357     if (!response)
358     {
359         OIC_LOG_V(ERROR, TAG, "%s: Client response is null",__func__);
360         return OC_STACK_INVALID_PARAM;
361     }
362
363     if (response->result < 4 && response->payload)
364     {
365         OIC_LOG_V(ERROR, TAG, "CSR sign error: result: %d, payload null: %s",
366                   response->result, response->payload ? "no" : "yes");
367         OIC_LOG_PAYLOAD(DEBUG, response->payload);
368         return OC_STACK_ERROR;
369     }
370
371     char *deviceId = 0;
372
373     if (!OCRepPayloadGetPropString((OCRepPayload *)response->payload,
374                                    OC_RSRVD_DEVICE_ID, &deviceId))
375     {
376         OIC_LOG(ERROR, TAG, "Can't get: Device Id");
377         result = OC_STACK_ERROR;
378     }
379
380     OicSecKey_t cert;
381     if (!OCRepPayloadGetPropPubDataType((OCRepPayload *)response->payload,
382                                    OC_RSRVD_CERT, &cert))
383     {
384         OIC_LOG_V(ERROR, TAG, "Can't get: %s", OC_RSRVD_CERT);
385         result = OC_STACK_ERROR;
386     }
387     else
388     {
389         OicSecKey_t key =
390         {
391             g_privateKey.bytes,
392             g_privateKey.len,
393             OIC_ENCODING_DER
394         };
395
396         uint16_t credId;
397         result = SRPSaveOwnCertChain(&cert, &key, &credId);
398         if (result != OC_STACK_OK)
399         {
400             OIC_LOG(ERROR, TAG, "Can't add cert");
401         }
402     }
403
404     //get cacert
405     OicSecKey_t caCert;
406     if (!OCRepPayloadGetPropPubDataType((OCRepPayload *)response->payload,
407                                    OC_RSRVD_CACERT, &caCert))
408     {
409         OIC_LOG_V(ERROR, TAG, "Can't get: %s", OC_RSRVD_CACERT);
410         result = OC_STACK_ERROR;
411     }
412     else
413     {
414         uint16_t credId;
415         result = SRPSaveTrustCertChain(caCert.data, caCert.len, caCert.encoding, &credId);
416         if (result != OC_STACK_OK)
417         {
418             OIC_LOG(ERROR, TAG, "Can't insert CA cert");
419         }
420     }
421
422     OICClearMemory(g_privateKey.bytes, g_privateKey.len);
423     OICFree(g_privateKey.bytes);
424     g_privateKey.bytes = NULL;
425     g_privateKey.len   = 0;
426
427     OIC_LOG_V(DEBUG, TAG, "OUT: %s", __func__);
428
429     return result;
430 }
431
432 /**
433  * Certificate-Issue request function
434  *
435  * @param[in] endPoint          cloud host and port
436  * @return  OCStackResult application result
437  */
438 OCStackResult OCCloudCertificateIssueRequest(void* ctx,
439                                              const OCDevAddr *endPoint,
440                                              OCCloudResponseCB callback)
441 {
442     OCStackResult ret = OC_STACK_OK;
443
444     OIC_LOG_V(DEBUG, TAG, "IN: %s", __func__);
445
446     if (NULL == endPoint)
447     {
448         OIC_LOG(ERROR, TAG, "Input parameter endpoint is NULL");
449         return OC_STACK_INVALID_PARAM;
450     }
451
452     char *deviceId = getDeviceId();
453
454     char subject[MAX_STRING_LEN] = { 0 };
455     CSRMakeSubject(subject, "KR", "Samsung", "OCF Device", deviceId);
456
457     OIC_LOG_V(DEBUG, TAG, "Certificate Request subject: %s", subject);
458
459     OCByteString request = {0};
460     if (0 != GenerateCSR(subject, &request))
461     {
462         OIC_LOG(ERROR, TAG, "Cann't get the sertificate request");
463         ret = OC_STACK_ERROR;
464         goto exit;
465     }
466     OIC_LOG(DEBUG, TAG, "Certificate Request:");
467     OIC_LOG_BUFFER(DEBUG, TAG, request.bytes, request.len);
468
469     OIC_LOG(DEBUG, TAG, "Private Key:");
470     OIC_LOG_BUFFER(DEBUG, TAG, g_privateKey.bytes, g_privateKey.len);
471
472     OCRepPayload* payload = OCRepPayloadCreate();
473     if (!payload)
474     {
475         OIC_LOG(ERROR, TAG, "Failed to memory allocation");
476         ret = OC_STACK_ERROR;
477         goto exit;
478     }
479
480     OCRepPayloadSetPropString(payload, OC_RSRVD_DEVICE_ID, deviceId);
481
482     OicSecKey_t csr = {.data = request.bytes, .len = request.len, .encoding = OIC_ENCODING_DER};
483
484     OCRepPayloadSetPropPubDataType(payload, OC_RSRVD_CSR, &csr);
485
486     OIC_LOG_PAYLOAD(DEBUG, (OCPayload *)payload);
487
488     char uri[MAX_URI_QUERY] = { 0 };
489     snprintf(uri, MAX_URI_QUERY, DEFAULT_QUERY,
490              endPoint->addr, endPoint->port,
491              OC_RSRVD_PROV_CERT_URI);
492     OIC_LOG_V(DEBUG, TAG, "Certificate Request Query: %s", uri);
493
494     OCCallbackData cbData;
495     fillCallbackData(&cbData, ctx, callback, HandleCertificateIssueRequest, NULL);
496
497     ret = OCDoResource(NULL, OC_REST_POST, uri, NULL,
498                        (OCPayload *)payload,
499                        CT_ADAPTER_TCP,
500                        OC_LOW_QOS, &cbData, NULL, 0);
501
502     OIC_LOG_V(DEBUG, TAG, "OUT: %s", __func__);
503 exit:
504     OICFree(request.bytes);
505     return ret;
506 }