1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2024 Felix Fietkau <nbd@nbd.name>
6 #include <sys/random.h>
12 #include <mbedtls/entropy.h>
13 #include <mbedtls/x509_crt.h>
14 #include <mbedtls/ecp.h>
15 #include <mbedtls/rsa.h>
17 #include <ucode/module.h>
21 /* mbedtls < 3.x compat */
23 #define mbedtls_pk_parse_key(pk, key, keylen, passwd, passwdlen, random, random_ctx) \
24 mbedtls_pk_parse_key(pk, key, keylen, passwd, passwdlen)
27 static uc_resource_type_t
*uc_pk_type
, *uc_crt_type
;
28 static uc_value_t
*registry
;
33 mbedtls_x509write_cert crt
; /* must be first */
38 static unsigned int uc_reg_add(uc_value_t
*val
)
42 while (ucv_array_get(registry
, i
))
45 ucv_array_set(registry
, i
, ucv_get(val
));
50 int random_cb(void *ctx
, unsigned char *out
, size_t len
)
53 if (getrandom(out
, len
, 0) != (ssize_t
) len
)
54 return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED
;
59 f
= fopen("/dev/urandom", "r");
60 if (fread(out
, len
, 1, f
) != 1)
61 return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED
;
67 int64_t get_int_arg(uc_value_t
*obj
, const char *key
, int64_t defval
)
69 uc_value_t
*uval
= ucv_object_get(obj
, key
, NULL
);
75 val
= ucv_int64_get(uval
);
76 if (errno
|| val
< 0 || val
> INT_MAX
)
79 return val
? val
: defval
;
83 gen_rsa_key(mbedtls_pk_context
*pk
, uc_value_t
*arg
)
85 int64_t key_size
, exp
;
87 key_size
= get_int_arg(arg
, "size", 2048);
88 exp
= get_int_arg(arg
, "exponent", 65537);
89 if (key_size
< 0 || exp
< 0)
92 return mbedtls_rsa_gen_key(mbedtls_pk_rsa(*pk
), random_cb
, NULL
, key_size
, exp
);
96 gen_ec_key(mbedtls_pk_context
*pk
, uc_value_t
*arg
)
98 mbedtls_ecp_group_id curve
;
102 c_arg
= ucv_object_get(arg
, "curve", NULL
);
103 if (c_arg
&& ucv_type(c_arg
) != UC_STRING
)
106 c_name
= ucv_string_get(c_arg
);
108 curve
= MBEDTLS_ECP_DP_SECP256R1
;
110 const mbedtls_ecp_curve_info
*curve_info
;
111 curve_info
= mbedtls_ecp_curve_info_from_name(c_name
);
113 return MBEDTLS_ERR_PK_UNKNOWN_NAMED_CURVE
;
115 curve
= curve_info
->grp_id
;
118 return mbedtls_ecp_gen_key(curve
, mbedtls_pk_ec(*pk
), random_cb
, NULL
);
121 static void free_pk(void *pk
)
130 static void free_crt(void *ptr
)
132 struct uc_cert_wr
*crt
= ptr
;
137 mbedtls_x509write_crt_free(&crt
->crt
);
138 mbedtls_mpi_free(&crt
->mpi
);
139 ucv_array_set(registry
, crt
->reg
, NULL
);
144 uc_generate_key(uc_vm_t
*vm
, size_t nargs
)
146 uc_value_t
*cur
, *arg
= uc_fn_arg(0);
147 mbedtls_pk_type_t pk_type
;
148 mbedtls_pk_context
*pk
;
152 if (ucv_type(arg
) != UC_OBJECT
)
155 cur
= ucv_object_get(arg
, "type", NULL
);
156 type
= ucv_string_get(cur
);
160 if (!strcmp(type
, "rsa"))
161 pk_type
= MBEDTLS_PK_RSA
;
162 else if (!strcmp(type
, "ec"))
163 pk_type
= MBEDTLS_PK_ECKEY
;
167 pk
= calloc(1, sizeof(*pk
));
169 mbedtls_pk_setup(pk
, mbedtls_pk_info_from_type(pk_type
));
172 ret
= C(gen_rsa_key(pk
, arg
));
174 case MBEDTLS_PK_ECKEY
:
175 ret
= C(gen_ec_key(pk
, arg
));
186 return uc_resource_new(uc_pk_type
, pk
);
190 uc_load_key(uc_vm_t
*vm
, size_t nargs
)
192 uc_value_t
*keystr
= uc_fn_arg(0);
193 uc_value_t
*pub
= uc_fn_arg(1);
194 uc_value_t
*passwd
= uc_fn_arg(2);
195 mbedtls_pk_context
*pk
;
198 if (ucv_type(keystr
) != UC_STRING
||
199 (pub
&& ucv_type(pub
) != UC_BOOLEAN
) ||
200 (passwd
&& ucv_type(passwd
) != UC_STRING
))
203 pk
= calloc(1, sizeof(*pk
));
205 if (ucv_is_truish(pub
))
206 ret
= C(mbedtls_pk_parse_public_key(pk
, (const uint8_t *)ucv_string_get(keystr
),
207 ucv_string_length(keystr
) + 1));
209 ret
= C(mbedtls_pk_parse_key(pk
, (const uint8_t *)ucv_string_get(keystr
),
210 ucv_string_length(keystr
) + 1,
211 (const uint8_t *)ucv_string_get(passwd
),
212 ucv_string_length(passwd
) + 1,
219 return uc_resource_new(uc_pk_type
, pk
);
223 uc_cert_info_add(uc_value_t
*info
, const char *name
, int len
)
230 val
= ucv_string_new_length(buf
, len
);
231 ucv_object_add(info
, name
, ucv_get(val
));
235 uc_cert_info_add_name(uc_value_t
*info
, const char *name
, mbedtls_x509_name
*dn
)
239 len
= mbedtls_x509_dn_gets(buf
, sizeof(buf
), dn
);
240 uc_cert_info_add(info
, name
, len
);
244 uc_cert_info_add_time(uc_value_t
*info
, const char *name
, mbedtls_x509_time
*t
)
248 len
= snprintf(buf
, sizeof(buf
), "%04d%02d%02d%02d%02d%02d",
249 t
->year
, t
->mon
, t
->day
, t
->hour
, t
->min
, t
->sec
);
250 uc_cert_info_add(info
, name
, len
);
254 uc_cert_info(uc_vm_t
*vm
, size_t nargs
)
256 uc_value_t
*arg
= uc_fn_arg(0);
257 mbedtls_x509_crt crt
, *cur
;
258 uc_value_t
*ret
= NULL
;
260 if (ucv_type(arg
) != UC_STRING
)
263 mbedtls_x509_crt_init(&crt
);
264 if (C(mbedtls_x509_crt_parse(&crt
, (const void *)ucv_string_get(arg
), ucv_string_length(arg
) + 1)) < 0)
267 ret
= ucv_array_new(vm
);
268 for (cur
= &crt
; cur
&& cur
->version
!= 0; cur
= cur
->next
) {
269 uc_value_t
*info
= ucv_object_new(vm
);
272 ucv_array_push(ret
, ucv_get(info
));
273 ucv_object_add(info
, "version", ucv_int64_new(cur
->version
));
275 uc_cert_info_add_name(info
, "issuer", &cur
->issuer
);
276 uc_cert_info_add_name(info
, "subject", &cur
->issuer
);
277 uc_cert_info_add_time(info
, "valid_from", &cur
->valid_from
);
278 uc_cert_info_add_time(info
, "valid_to", &cur
->valid_to
);
280 len
= mbedtls_x509_serial_gets(buf
, sizeof(buf
), &cur
->serial
);
281 uc_cert_info_add(info
, "serial", len
);
285 mbedtls_x509_crt_free(&crt
);
290 uc_pk_pem(uc_vm_t
*vm
, size_t nargs
)
292 mbedtls_pk_context
*pk
= uc_fn_thisval("mbedtls.pk");
293 uc_value_t
*pub
= uc_fn_arg(0);
298 if (ucv_is_truish(pub
))
299 CHECK(mbedtls_pk_write_pubkey_pem(pk
, (void *)buf
, sizeof(buf
)));
301 CHECK(mbedtls_pk_write_key_pem(pk
, (void *)buf
, sizeof(buf
)));
303 return ucv_string_new(buf
);
307 uc_pk_der(uc_vm_t
*vm
, size_t nargs
)
309 mbedtls_pk_context
*pk
= uc_fn_thisval("mbedtls.pk");
310 uc_value_t
*pub
= uc_fn_arg(0);
316 if (ucv_is_truish(pub
))
317 len
= mbedtls_pk_write_pubkey_der(pk
, (void *)buf
, sizeof(buf
));
319 len
= mbedtls_pk_write_key_der(pk
, (void *)buf
, sizeof(buf
));
323 return ucv_string_new_length(buf
+ sizeof(buf
) - len
, len
);
327 uc_crt_pem(uc_vm_t
*vm
, size_t nargs
)
329 mbedtls_x509write_cert
*crt
= uc_fn_thisval("mbedtls.crt");
333 CHECK(mbedtls_x509write_crt_pem(crt
, (void *)buf
, sizeof(buf
), random_cb
, NULL
));
335 return ucv_string_new(buf
);
339 uc_crt_der(uc_vm_t
*vm
, size_t nargs
)
341 mbedtls_x509write_cert
*crt
= uc_fn_thisval("mbedtls.crt");
347 len
= mbedtls_x509write_crt_der(crt
, (void *)buf
, sizeof(buf
), random_cb
, NULL
);
351 return ucv_string_new_length(buf
, len
);
355 uc_cert_set_validity(mbedtls_x509write_cert
*crt
, uc_value_t
*arg
)
357 uc_value_t
*from
= ucv_array_get(arg
, 0);
358 uc_value_t
*to
= ucv_array_get(arg
, 1);
360 if (ucv_type(from
) != UC_STRING
|| ucv_type(to
) != UC_STRING
)
363 return mbedtls_x509write_crt_set_validity(crt
, ucv_string_get(from
), ucv_string_get(to
));
367 uc_cert_init(mbedtls_x509write_cert
*crt
, mbedtls_mpi
*mpi
, uc_value_t
*reg
, uc_value_t
*arg
)
375 mbedtls_mpi_init(mpi
);
376 mbedtls_x509write_crt_init(crt
);
377 mbedtls_x509write_crt_set_md_alg(crt
, MBEDTLS_MD_SHA256
);
379 ca
= ucv_is_truish(ucv_object_get(arg
, "ca", NULL
));
380 path_len
= get_int_arg(arg
, "max_pathlen", ca
? -1 : 0);
384 version
= get_int_arg(arg
, "version", 3);
385 if (version
< 0 || version
> 3)
388 serial
= get_int_arg(arg
, "serial", 1);
392 mbedtls_mpi_lset(mpi
, serial
);
393 mbedtls_x509write_crt_set_serial(crt
, mpi
);
394 mbedtls_x509write_crt_set_version(crt
, version
- 1);
395 CHECK_INT(mbedtls_x509write_crt_set_basic_constraints(crt
, ca
, path_len
));
397 cur
= ucv_object_get(arg
, "subject_name", NULL
);
398 if (ucv_type(cur
) == UC_STRING
)
399 CHECK_INT(mbedtls_x509write_crt_set_subject_name(crt
, ucv_string_get(cur
)));
402 cur
= ucv_object_get(arg
, "subject_key", NULL
);
404 mbedtls_pk_context
*key
= ucv_resource_data(cur
, "mbedtls.pk");
408 ucv_array_set(reg
, 0, ucv_get(cur
));
409 mbedtls_x509write_crt_set_subject_key(crt
, key
);
410 mbedtls_x509write_crt_set_subject_key_identifier(crt
);
414 cur
= ucv_object_get(arg
, "issuer_name", NULL
);
415 if (ucv_type(cur
) == UC_STRING
)
416 CHECK_INT(mbedtls_x509write_crt_set_issuer_name(crt
, ucv_string_get(cur
)));
419 cur
= ucv_object_get(arg
, "issuer_key", NULL
);
421 mbedtls_pk_context
*key
= ucv_resource_data(cur
, "mbedtls.pk");
425 ucv_array_set(reg
, 1, ucv_get(cur
));
426 mbedtls_x509write_crt_set_issuer_key(crt
, key
);
427 mbedtls_x509write_crt_set_authority_key_identifier(crt
);
431 cur
= ucv_object_get(arg
, "validity", NULL
);
432 if (ucv_type(cur
) != UC_ARRAY
|| ucv_array_length(cur
) != 2)
434 if (uc_cert_set_validity(crt
, cur
))
437 cur
= ucv_object_get(arg
, "key_usage", NULL
);
438 if (ucv_type(cur
) == UC_ARRAY
) {
439 static const struct {
443 { "digital_signature", MBEDTLS_X509_KU_DIGITAL_SIGNATURE
},
444 { "non_repudiation", MBEDTLS_X509_KU_NON_REPUDIATION
},
445 { "key_encipherment", MBEDTLS_X509_KU_KEY_ENCIPHERMENT
},
446 { "data_encipherment", MBEDTLS_X509_KU_DATA_ENCIPHERMENT
},
447 { "key_agreement", MBEDTLS_X509_KU_KEY_AGREEMENT
},
448 { "key_cert_sign", MBEDTLS_X509_KU_KEY_CERT_SIGN
},
449 { "crl_sign", MBEDTLS_X509_KU_CRL_SIGN
},
451 uint8_t key_usage
= 0;
452 size_t len
= ucv_array_length(cur
);
454 for (size_t i
= 0; i
< len
; i
++) {
455 uc_value_t
*val
= ucv_array_get(cur
, i
);
459 str
= ucv_string_get(val
);
463 for (k
= 0; k
< ARRAY_SIZE(key_flags
); k
++)
464 if (!strcmp(str
, key_flags
[k
].name
))
466 if (k
== ARRAY_SIZE(key_flags
))
469 key_usage
|= key_flags
[k
].val
;
471 CHECK_INT(mbedtls_x509write_crt_set_key_usage(crt
, key_usage
));
475 #ifndef MBEDTLS_LEGACY
476 cur
= ucv_object_get(arg
, "ext_key_usage", NULL
);
477 if (ucv_type(cur
) == UC_ARRAY
&& ucv_array_length(cur
)) {
478 static const struct {
480 struct mbedtls_asn1_buf val
;
482 #define __oid(name, val) \
486 .tag = MBEDTLS_ASN1_OID, \
487 .len = sizeof(MBEDTLS_OID_##val), \
488 .p = (uint8_t *)MBEDTLS_OID_##val, \
491 __oid("server_auth", SERVER_AUTH
),
492 __oid("client_auth", CLIENT_AUTH
),
493 __oid("code_signing", CODE_SIGNING
),
494 __oid("email_protection", EMAIL_PROTECTION
),
495 __oid("time_stamping", TIME_STAMPING
),
496 __oid("ocsp_signing", OCSP_SIGNING
),
497 __oid("any", ANY_EXTENDED_KEY_USAGE
)
499 struct mbedtls_asn1_sequence
*elem
;
500 size_t len
= ucv_array_length(cur
);
502 elem
= calloc(len
, sizeof(*elem
));
503 for (size_t i
= 0; i
< len
; i
++) {
504 uc_value_t
*val
= ucv_array_get(cur
, i
);
508 str
= ucv_string_get(val
);
512 for (k
= 0; k
< ARRAY_SIZE(key_flags
); k
++)
513 if (!strcmp(str
, key_flags
[k
].name
))
516 if (k
== ARRAY_SIZE(key_flags
)) {
520 elem
[i
].buf
= key_flags
[k
].val
;
522 elem
[i
].next
= &elem
[i
+ 1];
525 CHECK_INT(mbedtls_x509write_crt_set_ext_key_usage(crt
, elem
));
534 uc_generate_cert(uc_vm_t
*vm
, size_t nargs
)
536 struct uc_cert_wr
*crt
;
537 uc_value_t
*arg
= uc_fn_arg(0);
540 if (ucv_type(arg
) != UC_OBJECT
)
543 reg
= ucv_array_new(vm
);
544 crt
= calloc(1, sizeof(*crt
));
545 if (C(uc_cert_init(&crt
->crt
, &crt
->mpi
, reg
, arg
))) {
550 crt
->reg
= uc_reg_add(reg
);
552 return uc_resource_new(uc_crt_type
, crt
);
556 uc_mbedtls_error(uc_vm_t
*vm
, size_t nargs
)
558 mbedtls_strerror(mbedtls_errno
, buf
, sizeof(buf
));
560 return ucv_string_new(buf
);
564 uc_mbedtls_errno(uc_vm_t
*vm
, size_t nargs
)
566 return ucv_int64_new(mbedtls_errno
);
570 static const uc_function_list_t pk_fns
[] = {
571 { "pem", uc_pk_pem
},
572 { "der", uc_pk_der
},
575 static const uc_function_list_t crt_fns
[] = {
576 { "pem", uc_crt_pem
},
577 { "der", uc_crt_der
},
580 static const uc_function_list_t global_fns
[] = {
581 { "load_key", uc_load_key
},
582 { "cert_info", uc_cert_info
},
583 { "generate_key", uc_generate_key
},
584 { "generate_cert", uc_generate_cert
},
585 { "generate_pkcs12", uc_generate_pkcs12
},
586 { "errno", uc_mbedtls_errno
},
587 { "error", uc_mbedtls_error
},
590 void uc_module_init(uc_vm_t
*vm
, uc_value_t
*scope
)
592 uc_pk_type
= uc_type_declare(vm
, "mbedtls.pk", pk_fns
, free_pk
);
593 uc_crt_type
= uc_type_declare(vm
, "mbedtls.crt", crt_fns
, free_crt
);
594 uc_function_list_register(scope
, global_fns
);
596 registry
= ucv_array_new(vm
);
597 uc_vm_registry_set(vm
, "pkgen.registry", registry
);