diff --git a/include/mbedtls/oid.h b/include/mbedtls/oid.h index a72f51c4f7ae..c6a4c93ac372 100644 --- a/include/mbedtls/oid.h +++ b/include/mbedtls/oid.h @@ -320,6 +320,7 @@ /* * PKCS#8 OIDs */ +#define MBEDTLS_OID_PKCS9_CSR_CHAL_PW MBEDTLS_OID_PKCS9 "\x07" /**< challenge password OBJECT IDENTIFIER ::= {pkcs-9 7 } */ #define MBEDTLS_OID_PKCS9_CSR_EXT_REQ MBEDTLS_OID_PKCS9 "\x0e" /**< extensionRequest OBJECT IDENTIFIER ::= {pkcs-9 14} */ /* diff --git a/include/mbedtls/x509.h b/include/mbedtls/x509.h index 8dfd1f364cf6..77db980357b3 100644 --- a/include/mbedtls/x509.h +++ b/include/mbedtls/x509.h @@ -208,6 +208,7 @@ #define MBEDTLS_X509_FORMAT_PEM 2 #define MBEDTLS_X509_MAX_DN_NAME_SIZE 256 /**< Maximum value size of a DN entry */ +#define MBEDTLS_X509_MAX_PKCS9_STR 255 /** pkcs-9-ub-pkcs9String INTEGER ::= 255 */ #ifdef __cplusplus extern "C" { @@ -461,6 +462,8 @@ int mbedtls_x509_write_names(unsigned char **p, unsigned char *start, int mbedtls_x509_write_sig(unsigned char **p, unsigned char *start, const char *oid, size_t oid_len, unsigned char *sig, size_t size); +int mbedtls_x509_write_challenge_password(unsigned char **p, unsigned char *start, + mbedtls_asn1_buf *chal_pw); int mbedtls_x509_get_ns_cert_type(unsigned char **p, const unsigned char *end, unsigned char *ns_cert_type); diff --git a/include/mbedtls/x509_csr.h b/include/mbedtls/x509_csr.h index f3f9e13a0365..6db7c32b92ca 100644 --- a/include/mbedtls/x509_csr.h +++ b/include/mbedtls/x509_csr.h @@ -80,6 +80,7 @@ typedef struct mbedtls_x509write_csr { mbedtls_asn1_named_data *MBEDTLS_PRIVATE(subject); mbedtls_md_type_t MBEDTLS_PRIVATE(md_alg); mbedtls_asn1_named_data *MBEDTLS_PRIVATE(extensions); + mbedtls_asn1_buf MBEDTLS_PRIVATE(chal_pw); } mbedtls_x509write_csr; @@ -278,6 +279,19 @@ int mbedtls_x509write_csr_set_extension(mbedtls_x509write_csr *ctx, int critical, const unsigned char *val, size_t val_len); +/** + * \brief Set a CSR challenge password + * + * \param ctx CSR context to use + * \param chal_pw challenge password OCTET STRING + * \param chal_pw_len length of the challenge password data + * \param printable tag as printable string (\c 1) or UTF8 string (\c 0) + * + * \return 0 if successful, or a MBEDTLS_ERR_X509_BAD_INPUT_DATA + */ +int mbedtls_x509write_csr_set_challenge_password(mbedtls_x509write_csr *ctx, + unsigned char *chal_pw, size_t chal_pw_len, + int printable); /** * \brief Free the contents of a CSR context * diff --git a/library/x509_create.c b/library/x509_create.c index 50db95688ff0..73d2e555f388 100644 --- a/library/x509_create.c +++ b/library/x509_create.c @@ -362,6 +362,37 @@ int mbedtls_x509_write_extensions(unsigned char **p, unsigned char *start, cur_ext = cur_ext->next; } + MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, start, len)); + MBEDTLS_ASN1_CHK_ADD(len, + mbedtls_asn1_write_tag(p, start, + MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE)); + + return (int) len; +} + +/* + * challengePassword ATTRIBUTE ::= { + * WITH SYNTAX PKCS9String + * EQUALITY MATCHING RULE caseExactMatch + * SINGLE VALUE TRUE + * ID pkcs-9-at-challengePassword + */ +int mbedtls_x509_write_challenge_password(unsigned char **p, unsigned char *start, + mbedtls_asn1_buf *chal_pw) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t len = 0; + int (*str_writer)(unsigned char **, const unsigned char *, + const char *, size_t) = &mbedtls_asn1_write_printable_string; + + if (chal_pw->tag == MBEDTLS_ASN1_UTF8_STRING) { + str_writer = &mbedtls_asn1_write_utf8_string; + } + + MBEDTLS_ASN1_CHK_ADD(len, + (*str_writer)(p, start, (const char *) chal_pw->p, chal_pw->len)); + return (int) len; } diff --git a/library/x509write_crt.c b/library/x509write_crt.c index 70d7e93db2ef..482ff0797bff 100644 --- a/library/x509write_crt.c +++ b/library/x509write_crt.c @@ -468,11 +468,6 @@ int mbedtls_x509write_crt_der(mbedtls_x509write_cert *ctx, mbedtls_x509_write_extensions(&c, buf, ctx->extensions)); 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_CONTEXT_SPECIFIC | diff --git a/library/x509write_csr.c b/library/x509write_csr.c index deb66174b240..9f35cf133694 100644 --- a/library/x509write_csr.c +++ b/library/x509write_csr.c @@ -232,6 +232,71 @@ int mbedtls_x509write_csr_set_ns_cert_type(mbedtls_x509write_csr *ctx, return 0; } +int mbedtls_x509write_csr_set_challenge_password(mbedtls_x509write_csr *ctx, + unsigned char *chal_pw, + size_t chal_pw_len, + int printable) +{ + if (chal_pw_len == 0 || chal_pw == NULL) { + return MBEDTLS_ERR_X509_BAD_INPUT_DATA; + } + + /* pkcs-9-ub-challengePassword INTEGER ::= pkcs-9-ub-pkcs9String */ + if (chal_pw_len > MBEDTLS_X509_MAX_PKCS9_STR) { + return MBEDTLS_ERR_X509_BAD_INPUT_DATA; + } + + if (printable == 0) { + ctx->chal_pw.tag = MBEDTLS_ASN1_UTF8_STRING; + } else { + ctx->chal_pw.tag = MBEDTLS_ASN1_PRINTABLE_STRING; + } + + ctx->chal_pw.len = chal_pw_len; + ctx->chal_pw.p = chal_pw; + + return 0; +} + +/* + * RFC 2986 - 4.1 CertificationRequestInfo + * + * Attributes { ATTRIBUTE:IOSet } ::= SET OF Attribute{{ IOSet }} + * + * CRIAttributes ATTRIBUTE ::= { + * ... -- add any locally defined attributes here -- } + * + * Attribute { ATTRIBUTE:IOSet } ::= SEQUENCE { + * type ATTRIBUTE.&id({IOSet}), + * values SET SIZE(1..MAX) OF ATTRIBUTE.&Type({IOSet}{@type}) + * } + * + */ +static int x509write_csr_attribute(unsigned char **p, + unsigned char *start, + const char *oid, size_t oid_len, + size_t val_len) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t len = val_len; + + MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, start, len)); + MBEDTLS_ASN1_CHK_ADD(len, + mbedtls_asn1_write_tag( + p, start, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SET)); + + MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_oid(p, start, oid, oid_len)); + + MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, start, len)); + MBEDTLS_ASN1_CHK_ADD(len, + mbedtls_asn1_write_tag( + p, start, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)); + + return (int) (len - val_len); +} + static int x509write_csr_der_internal(mbedtls_x509write_csr *ctx, unsigned char *buf, size_t size, @@ -255,32 +320,34 @@ static int x509write_csr_der_internal(mbedtls_x509write_csr *ctx, /* 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 (ctx->extensions != NULL) { + size_t attr_len = 0; - if (len) { - MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len)); - MBEDTLS_ASN1_CHK_ADD(len, - mbedtls_asn1_write_tag( + MBEDTLS_ASN1_CHK_ADD(attr_len, + mbedtls_x509_write_extensions(&c, buf, ctx->extensions)); + MBEDTLS_ASN1_CHK_ADD(attr_len, + x509write_csr_attribute( &c, buf, - MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)); + MBEDTLS_OID_PKCS9_CSR_EXT_REQ, + MBEDTLS_OID_SIZE(MBEDTLS_OID_PKCS9_CSR_EXT_REQ), + attr_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_SET)); + len += attr_len; + } - 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))); + if (ctx->chal_pw.p != NULL) { + size_t attr_len = 0; - MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len)); - MBEDTLS_ASN1_CHK_ADD(len, - mbedtls_asn1_write_tag( + MBEDTLS_ASN1_CHK_ADD(attr_len, + mbedtls_x509_write_challenge_password(&c, buf, &(ctx->chal_pw))); + MBEDTLS_ASN1_CHK_ADD(attr_len, + x509write_csr_attribute( &c, buf, - MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)); + MBEDTLS_OID_PKCS9_CSR_CHAL_PW, + MBEDTLS_OID_SIZE(MBEDTLS_OID_PKCS9_CSR_CHAL_PW), + attr_len)); + + len += attr_len; } MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len));