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