mirror of
https://github.com/ARMmbed/mbedtls.git
synced 2025-06-25 22:56:35 +08:00

Some code that parses or writes X.509 needs to know OID values. We provide a convenient list. Don't remove this list from the public interface of the library. For user convenience, expose these values in the same header as before and with the same name as before: `MBEDTLS_OID_xxx` in `<mbedtls/oid.h>`. Signed-off-by: Gilles Peskine <Gilles.Peskine@arm.com>
316 lines
9.9 KiB
C
316 lines
9.9 KiB
C
/*
|
|
* X.509 Certificate Signing Request writing
|
|
*
|
|
* Copyright The Mbed TLS Contributors
|
|
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
|
|
*/
|
|
/*
|
|
* References:
|
|
* - CSRs: PKCS#10 v1.7 aka RFC 2986
|
|
* - attributes: PKCS#9 v2.0 aka RFC 2985
|
|
*/
|
|
|
|
#include "x509_internal.h"
|
|
|
|
#if defined(MBEDTLS_X509_CSR_WRITE_C)
|
|
|
|
#include "mbedtls/x509_csr.h"
|
|
#include "mbedtls/asn1write.h"
|
|
#include "mbedtls/error.h"
|
|
#include "mbedtls/oid.h"
|
|
#include "x509_oid.h"
|
|
#include "mbedtls/platform_util.h"
|
|
|
|
#include "psa/crypto.h"
|
|
#include "psa_util_internal.h"
|
|
#include "mbedtls/psa_util.h"
|
|
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
#if defined(MBEDTLS_PEM_WRITE_C)
|
|
#include "mbedtls/pem.h"
|
|
#endif
|
|
|
|
#include "mbedtls/platform.h"
|
|
|
|
void mbedtls_x509write_csr_init(mbedtls_x509write_csr *ctx)
|
|
{
|
|
memset(ctx, 0, sizeof(mbedtls_x509write_csr));
|
|
}
|
|
|
|
void mbedtls_x509write_csr_free(mbedtls_x509write_csr *ctx)
|
|
{
|
|
if (ctx == NULL) {
|
|
return;
|
|
}
|
|
|
|
mbedtls_asn1_free_named_data_list(&ctx->subject);
|
|
mbedtls_asn1_free_named_data_list(&ctx->extensions);
|
|
|
|
mbedtls_platform_zeroize(ctx, sizeof(mbedtls_x509write_csr));
|
|
}
|
|
|
|
void mbedtls_x509write_csr_set_md_alg(mbedtls_x509write_csr *ctx, mbedtls_md_type_t md_alg)
|
|
{
|
|
ctx->md_alg = md_alg;
|
|
}
|
|
|
|
void mbedtls_x509write_csr_set_key(mbedtls_x509write_csr *ctx, mbedtls_pk_context *key)
|
|
{
|
|
ctx->key = key;
|
|
}
|
|
|
|
int mbedtls_x509write_csr_set_subject_name(mbedtls_x509write_csr *ctx,
|
|
const char *subject_name)
|
|
{
|
|
return mbedtls_x509_string_to_names(&ctx->subject, subject_name);
|
|
}
|
|
|
|
int mbedtls_x509write_csr_set_extension(mbedtls_x509write_csr *ctx,
|
|
const char *oid, size_t oid_len,
|
|
int critical,
|
|
const unsigned char *val, size_t val_len)
|
|
{
|
|
return mbedtls_x509_set_extension(&ctx->extensions, oid, oid_len,
|
|
critical, val, val_len);
|
|
}
|
|
|
|
int mbedtls_x509write_csr_set_subject_alternative_name(mbedtls_x509write_csr *ctx,
|
|
const mbedtls_x509_san_list *san_list)
|
|
{
|
|
return mbedtls_x509_write_set_san_common(&ctx->extensions, san_list);
|
|
}
|
|
|
|
int mbedtls_x509write_csr_set_key_usage(mbedtls_x509write_csr *ctx, unsigned char key_usage)
|
|
{
|
|
unsigned char buf[4] = { 0 };
|
|
unsigned char *c;
|
|
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
|
|
|
|
c = buf + 4;
|
|
|
|
ret = mbedtls_asn1_write_named_bitstring(&c, buf, &key_usage, 8);
|
|
if (ret < 3 || ret > 4) {
|
|
return ret;
|
|
}
|
|
|
|
ret = mbedtls_x509write_csr_set_extension(ctx, MBEDTLS_OID_KEY_USAGE,
|
|
MBEDTLS_OID_SIZE(MBEDTLS_OID_KEY_USAGE),
|
|
0, c, (size_t) ret);
|
|
if (ret != 0) {
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int mbedtls_x509write_csr_set_ns_cert_type(mbedtls_x509write_csr *ctx,
|
|
unsigned char ns_cert_type)
|
|
{
|
|
unsigned char buf[4] = { 0 };
|
|
unsigned char *c;
|
|
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
|
|
|
|
c = buf + 4;
|
|
|
|
ret = mbedtls_asn1_write_named_bitstring(&c, buf, &ns_cert_type, 8);
|
|
if (ret < 3 || ret > 4) {
|
|
return ret;
|
|
}
|
|
|
|
ret = mbedtls_x509write_csr_set_extension(ctx, MBEDTLS_OID_NS_CERT_TYPE,
|
|
MBEDTLS_OID_SIZE(MBEDTLS_OID_NS_CERT_TYPE),
|
|
0, c, (size_t) ret);
|
|
if (ret != 0) {
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int x509write_csr_der_internal(mbedtls_x509write_csr *ctx,
|
|
unsigned char *buf,
|
|
size_t size,
|
|
unsigned char *sig, size_t sig_size)
|
|
{
|
|
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
|
|
const char *sig_oid;
|
|
size_t sig_oid_len = 0;
|
|
unsigned char *c, *c2;
|
|
unsigned char hash[MBEDTLS_MD_MAX_SIZE];
|
|
size_t pub_len = 0, sig_and_oid_len = 0, sig_len;
|
|
size_t len = 0;
|
|
mbedtls_pk_type_t pk_alg;
|
|
size_t hash_len;
|
|
psa_algorithm_t hash_alg = mbedtls_md_psa_alg_from_type(ctx->md_alg);
|
|
|
|
/* Write the CSR backwards starting from the end of buf */
|
|
c = buf + size;
|
|
|
|
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_x509_write_extensions(&c, buf,
|
|
ctx->extensions));
|
|
|
|
if (len) {
|
|
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len));
|
|
MBEDTLS_ASN1_CHK_ADD(len,
|
|
mbedtls_asn1_write_tag(
|
|
&c, buf,
|
|
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE));
|
|
|
|
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len));
|
|
MBEDTLS_ASN1_CHK_ADD(len,
|
|
mbedtls_asn1_write_tag(
|
|
&c, buf,
|
|
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SET));
|
|
|
|
MBEDTLS_ASN1_CHK_ADD(len,
|
|
mbedtls_asn1_write_oid(
|
|
&c, buf, MBEDTLS_OID_PKCS9_CSR_EXT_REQ,
|
|
MBEDTLS_OID_SIZE(MBEDTLS_OID_PKCS9_CSR_EXT_REQ)));
|
|
|
|
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len));
|
|
MBEDTLS_ASN1_CHK_ADD(len,
|
|
mbedtls_asn1_write_tag(
|
|
&c, buf,
|
|
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE));
|
|
}
|
|
|
|
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len));
|
|
MBEDTLS_ASN1_CHK_ADD(len,
|
|
mbedtls_asn1_write_tag(
|
|
&c, buf,
|
|
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC));
|
|
|
|
MBEDTLS_ASN1_CHK_ADD(pub_len, mbedtls_pk_write_pubkey_der(ctx->key,
|
|
buf, (size_t) (c - buf)));
|
|
c -= pub_len;
|
|
len += pub_len;
|
|
|
|
/*
|
|
* Subject ::= Name
|
|
*/
|
|
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_x509_write_names(&c, buf,
|
|
ctx->subject));
|
|
|
|
/*
|
|
* Version ::= INTEGER { v1(0), v2(1), v3(2) }
|
|
*/
|
|
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_int(&c, buf, 0));
|
|
|
|
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len));
|
|
MBEDTLS_ASN1_CHK_ADD(len,
|
|
mbedtls_asn1_write_tag(
|
|
&c, buf,
|
|
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE));
|
|
|
|
/*
|
|
* Sign the written CSR data into the sig buffer
|
|
* Note: hash errors can happen only after an internal error
|
|
*/
|
|
if (psa_hash_compute(hash_alg,
|
|
c,
|
|
len,
|
|
hash,
|
|
sizeof(hash),
|
|
&hash_len) != PSA_SUCCESS) {
|
|
return MBEDTLS_ERR_PLATFORM_HW_ACCEL_FAILED;
|
|
}
|
|
if ((ret = mbedtls_pk_sign(ctx->key, ctx->md_alg, hash, 0,
|
|
sig, sig_size, &sig_len)) != 0) {
|
|
return ret;
|
|
}
|
|
|
|
if (mbedtls_pk_can_do(ctx->key, MBEDTLS_PK_RSA)) {
|
|
pk_alg = MBEDTLS_PK_RSA;
|
|
} else if (mbedtls_pk_can_do(ctx->key, MBEDTLS_PK_ECDSA)) {
|
|
pk_alg = MBEDTLS_PK_ECDSA;
|
|
} else {
|
|
return MBEDTLS_ERR_X509_INVALID_ALG;
|
|
}
|
|
|
|
if ((ret = mbedtls_x509_oid_get_oid_by_sig_alg(pk_alg, ctx->md_alg,
|
|
&sig_oid, &sig_oid_len)) != 0) {
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* Move the written CSR data to the start of buf to create space for
|
|
* writing the signature into buf.
|
|
*/
|
|
memmove(buf, c, len);
|
|
|
|
/*
|
|
* Write sig and its OID into buf backwards from the end of buf.
|
|
* Note: mbedtls_x509_write_sig will check for c2 - ( buf + len ) < sig_len
|
|
* and return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL if needed.
|
|
*/
|
|
c2 = buf + size;
|
|
MBEDTLS_ASN1_CHK_ADD(sig_and_oid_len,
|
|
mbedtls_x509_write_sig(&c2, buf + len, sig_oid, sig_oid_len,
|
|
sig, sig_len, pk_alg));
|
|
|
|
/*
|
|
* Compact the space between the CSR data and signature by moving the
|
|
* CSR data to the start of the signature.
|
|
*/
|
|
c2 -= len;
|
|
memmove(c2, buf, len);
|
|
|
|
/* ASN encode the total size and tag the CSR data with it. */
|
|
len += sig_and_oid_len;
|
|
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c2, buf, len));
|
|
MBEDTLS_ASN1_CHK_ADD(len,
|
|
mbedtls_asn1_write_tag(
|
|
&c2, buf,
|
|
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE));
|
|
|
|
/* Zero the unused bytes at the start of buf */
|
|
memset(buf, 0, (size_t) (c2 - buf));
|
|
|
|
return (int) len;
|
|
}
|
|
|
|
int mbedtls_x509write_csr_der(mbedtls_x509write_csr *ctx, unsigned char *buf,
|
|
size_t size)
|
|
{
|
|
int ret;
|
|
unsigned char *sig;
|
|
|
|
if ((sig = mbedtls_calloc(1, MBEDTLS_PK_SIGNATURE_MAX_SIZE)) == NULL) {
|
|
return MBEDTLS_ERR_X509_ALLOC_FAILED;
|
|
}
|
|
|
|
ret = x509write_csr_der_internal(ctx, buf, size,
|
|
sig, MBEDTLS_PK_SIGNATURE_MAX_SIZE);
|
|
|
|
mbedtls_free(sig);
|
|
|
|
return ret;
|
|
}
|
|
|
|
#define PEM_BEGIN_CSR "-----BEGIN CERTIFICATE REQUEST-----\n"
|
|
#define PEM_END_CSR "-----END CERTIFICATE REQUEST-----\n"
|
|
|
|
#if defined(MBEDTLS_PEM_WRITE_C)
|
|
int mbedtls_x509write_csr_pem(mbedtls_x509write_csr *ctx, unsigned char *buf, size_t size)
|
|
{
|
|
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
|
|
size_t olen = 0;
|
|
|
|
if ((ret = mbedtls_x509write_csr_der(ctx, buf, size)) < 0) {
|
|
return ret;
|
|
}
|
|
|
|
if ((ret = mbedtls_pem_write_buffer(PEM_BEGIN_CSR, PEM_END_CSR,
|
|
buf + size - ret,
|
|
ret, buf, size, &olen)) != 0) {
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif /* MBEDTLS_PEM_WRITE_C */
|
|
|
|
#endif /* MBEDTLS_X509_CSR_WRITE_C */
|