d76a26e086
Keep applying the windows entropy patch (UWP support).
Remove no longer needed padlock patch.
Update thirdparty README to reflect changes, and new source inclusion
criteria.
(cherry picked from commit e375cbd094
)
414 lines
11 KiB
C
414 lines
11 KiB
C
/*
|
|
* X.509 Certificate Signing Request (CSR) parsing
|
|
*
|
|
* Copyright The Mbed TLS Contributors
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
* not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
/*
|
|
* The ITU-T X.509 standard defines a certificate format for PKI.
|
|
*
|
|
* http://www.ietf.org/rfc/rfc5280.txt (Certificates and CRLs)
|
|
* http://www.ietf.org/rfc/rfc3279.txt (Alg IDs for CRLs)
|
|
* http://www.ietf.org/rfc/rfc2986.txt (CSRs, aka PKCS#10)
|
|
*
|
|
* http://www.itu.int/ITU-T/studygroups/com17/languages/X.680-0207.pdf
|
|
* http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf
|
|
*/
|
|
|
|
#include "common.h"
|
|
|
|
#if defined(MBEDTLS_X509_CSR_PARSE_C)
|
|
|
|
#include "mbedtls/x509_csr.h"
|
|
#include "mbedtls/error.h"
|
|
#include "mbedtls/oid.h"
|
|
#include "mbedtls/platform_util.h"
|
|
|
|
#include <string.h>
|
|
|
|
#if defined(MBEDTLS_PEM_PARSE_C)
|
|
#include "mbedtls/pem.h"
|
|
#endif
|
|
|
|
#if defined(MBEDTLS_PLATFORM_C)
|
|
#include "mbedtls/platform.h"
|
|
#else
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#define mbedtls_free free
|
|
#define mbedtls_calloc calloc
|
|
#define mbedtls_snprintf snprintf
|
|
#endif
|
|
|
|
#if defined(MBEDTLS_FS_IO) || defined(EFIX64) || defined(EFI32)
|
|
#include <stdio.h>
|
|
#endif
|
|
|
|
/*
|
|
* Version ::= INTEGER { v1(0) }
|
|
*/
|
|
static int x509_csr_get_version( unsigned char **p,
|
|
const unsigned char *end,
|
|
int *ver )
|
|
{
|
|
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
|
|
|
|
if( ( ret = mbedtls_asn1_get_int( p, end, ver ) ) != 0 )
|
|
{
|
|
if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG )
|
|
{
|
|
*ver = 0;
|
|
return( 0 );
|
|
}
|
|
|
|
return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_VERSION, ret ) );
|
|
}
|
|
|
|
return( 0 );
|
|
}
|
|
|
|
/*
|
|
* Parse a CSR in DER format
|
|
*/
|
|
int mbedtls_x509_csr_parse_der( mbedtls_x509_csr *csr,
|
|
const unsigned char *buf, size_t buflen )
|
|
{
|
|
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
|
|
size_t len;
|
|
unsigned char *p, *end;
|
|
mbedtls_x509_buf sig_params;
|
|
|
|
memset( &sig_params, 0, sizeof( mbedtls_x509_buf ) );
|
|
|
|
/*
|
|
* Check for valid input
|
|
*/
|
|
if( csr == NULL || buf == NULL || buflen == 0 )
|
|
return( MBEDTLS_ERR_X509_BAD_INPUT_DATA );
|
|
|
|
mbedtls_x509_csr_init( csr );
|
|
|
|
/*
|
|
* first copy the raw DER data
|
|
*/
|
|
p = mbedtls_calloc( 1, len = buflen );
|
|
|
|
if( p == NULL )
|
|
return( MBEDTLS_ERR_X509_ALLOC_FAILED );
|
|
|
|
memcpy( p, buf, buflen );
|
|
|
|
csr->raw.p = p;
|
|
csr->raw.len = len;
|
|
end = p + len;
|
|
|
|
/*
|
|
* CertificationRequest ::= SEQUENCE {
|
|
* certificationRequestInfo CertificationRequestInfo,
|
|
* signatureAlgorithm AlgorithmIdentifier,
|
|
* signature BIT STRING
|
|
* }
|
|
*/
|
|
if( ( ret = mbedtls_asn1_get_tag( &p, end, &len,
|
|
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
|
|
{
|
|
mbedtls_x509_csr_free( csr );
|
|
return( MBEDTLS_ERR_X509_INVALID_FORMAT );
|
|
}
|
|
|
|
if( len != (size_t) ( end - p ) )
|
|
{
|
|
mbedtls_x509_csr_free( csr );
|
|
return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_FORMAT,
|
|
MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ) );
|
|
}
|
|
|
|
/*
|
|
* CertificationRequestInfo ::= SEQUENCE {
|
|
*/
|
|
csr->cri.p = p;
|
|
|
|
if( ( ret = mbedtls_asn1_get_tag( &p, end, &len,
|
|
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
|
|
{
|
|
mbedtls_x509_csr_free( csr );
|
|
return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_FORMAT, ret ) );
|
|
}
|
|
|
|
end = p + len;
|
|
csr->cri.len = end - csr->cri.p;
|
|
|
|
/*
|
|
* Version ::= INTEGER { v1(0) }
|
|
*/
|
|
if( ( ret = x509_csr_get_version( &p, end, &csr->version ) ) != 0 )
|
|
{
|
|
mbedtls_x509_csr_free( csr );
|
|
return( ret );
|
|
}
|
|
|
|
if( csr->version != 0 )
|
|
{
|
|
mbedtls_x509_csr_free( csr );
|
|
return( MBEDTLS_ERR_X509_UNKNOWN_VERSION );
|
|
}
|
|
|
|
csr->version++;
|
|
|
|
/*
|
|
* subject Name
|
|
*/
|
|
csr->subject_raw.p = p;
|
|
|
|
if( ( ret = mbedtls_asn1_get_tag( &p, end, &len,
|
|
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
|
|
{
|
|
mbedtls_x509_csr_free( csr );
|
|
return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_FORMAT, ret ) );
|
|
}
|
|
|
|
if( ( ret = mbedtls_x509_get_name( &p, p + len, &csr->subject ) ) != 0 )
|
|
{
|
|
mbedtls_x509_csr_free( csr );
|
|
return( ret );
|
|
}
|
|
|
|
csr->subject_raw.len = p - csr->subject_raw.p;
|
|
|
|
/*
|
|
* subjectPKInfo SubjectPublicKeyInfo
|
|
*/
|
|
if( ( ret = mbedtls_pk_parse_subpubkey( &p, end, &csr->pk ) ) != 0 )
|
|
{
|
|
mbedtls_x509_csr_free( csr );
|
|
return( ret );
|
|
}
|
|
|
|
/*
|
|
* attributes [0] Attributes
|
|
*
|
|
* The list of possible attributes is open-ended, though RFC 2985
|
|
* (PKCS#9) defines a few in section 5.4. We currently don't support any,
|
|
* so we just ignore them. This is a safe thing to do as the worst thing
|
|
* that could happen is that we issue a certificate that does not match
|
|
* the requester's expectations - this cannot cause a violation of our
|
|
* signature policies.
|
|
*/
|
|
if( ( ret = mbedtls_asn1_get_tag( &p, end, &len,
|
|
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC ) ) != 0 )
|
|
{
|
|
mbedtls_x509_csr_free( csr );
|
|
return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_FORMAT, ret ) );
|
|
}
|
|
|
|
p += len;
|
|
|
|
end = csr->raw.p + csr->raw.len;
|
|
|
|
/*
|
|
* signatureAlgorithm AlgorithmIdentifier,
|
|
* signature BIT STRING
|
|
*/
|
|
if( ( ret = mbedtls_x509_get_alg( &p, end, &csr->sig_oid, &sig_params ) ) != 0 )
|
|
{
|
|
mbedtls_x509_csr_free( csr );
|
|
return( ret );
|
|
}
|
|
|
|
if( ( ret = mbedtls_x509_get_sig_alg( &csr->sig_oid, &sig_params,
|
|
&csr->sig_md, &csr->sig_pk,
|
|
&csr->sig_opts ) ) != 0 )
|
|
{
|
|
mbedtls_x509_csr_free( csr );
|
|
return( MBEDTLS_ERR_X509_UNKNOWN_SIG_ALG );
|
|
}
|
|
|
|
if( ( ret = mbedtls_x509_get_sig( &p, end, &csr->sig ) ) != 0 )
|
|
{
|
|
mbedtls_x509_csr_free( csr );
|
|
return( ret );
|
|
}
|
|
|
|
if( p != end )
|
|
{
|
|
mbedtls_x509_csr_free( csr );
|
|
return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_X509_INVALID_FORMAT,
|
|
MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ) );
|
|
}
|
|
|
|
return( 0 );
|
|
}
|
|
|
|
/*
|
|
* Parse a CSR, allowing for PEM or raw DER encoding
|
|
*/
|
|
int mbedtls_x509_csr_parse( mbedtls_x509_csr *csr, const unsigned char *buf, size_t buflen )
|
|
{
|
|
#if defined(MBEDTLS_PEM_PARSE_C)
|
|
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
|
|
size_t use_len;
|
|
mbedtls_pem_context pem;
|
|
#endif
|
|
|
|
/*
|
|
* Check for valid input
|
|
*/
|
|
if( csr == NULL || buf == NULL || buflen == 0 )
|
|
return( MBEDTLS_ERR_X509_BAD_INPUT_DATA );
|
|
|
|
#if defined(MBEDTLS_PEM_PARSE_C)
|
|
/* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */
|
|
if( buf[buflen - 1] == '\0' )
|
|
{
|
|
mbedtls_pem_init( &pem );
|
|
ret = mbedtls_pem_read_buffer( &pem,
|
|
"-----BEGIN CERTIFICATE REQUEST-----",
|
|
"-----END CERTIFICATE REQUEST-----",
|
|
buf, NULL, 0, &use_len );
|
|
if( ret == MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT )
|
|
{
|
|
ret = mbedtls_pem_read_buffer( &pem,
|
|
"-----BEGIN NEW CERTIFICATE REQUEST-----",
|
|
"-----END NEW CERTIFICATE REQUEST-----",
|
|
buf, NULL, 0, &use_len );
|
|
}
|
|
|
|
if( ret == 0 )
|
|
{
|
|
/*
|
|
* Was PEM encoded, parse the result
|
|
*/
|
|
ret = mbedtls_x509_csr_parse_der( csr, pem.buf, pem.buflen );
|
|
}
|
|
|
|
mbedtls_pem_free( &pem );
|
|
if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT )
|
|
return( ret );
|
|
}
|
|
#endif /* MBEDTLS_PEM_PARSE_C */
|
|
return( mbedtls_x509_csr_parse_der( csr, buf, buflen ) );
|
|
}
|
|
|
|
#if defined(MBEDTLS_FS_IO)
|
|
/*
|
|
* Load a CSR into the structure
|
|
*/
|
|
int mbedtls_x509_csr_parse_file( mbedtls_x509_csr *csr, const char *path )
|
|
{
|
|
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
|
|
size_t n;
|
|
unsigned char *buf;
|
|
|
|
if( ( ret = mbedtls_pk_load_file( path, &buf, &n ) ) != 0 )
|
|
return( ret );
|
|
|
|
ret = mbedtls_x509_csr_parse( csr, buf, n );
|
|
|
|
mbedtls_platform_zeroize( buf, n );
|
|
mbedtls_free( buf );
|
|
|
|
return( ret );
|
|
}
|
|
#endif /* MBEDTLS_FS_IO */
|
|
|
|
#define BEFORE_COLON 14
|
|
#define BC "14"
|
|
/*
|
|
* Return an informational string about the CSR.
|
|
*/
|
|
int mbedtls_x509_csr_info( char *buf, size_t size, const char *prefix,
|
|
const mbedtls_x509_csr *csr )
|
|
{
|
|
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
|
|
size_t n;
|
|
char *p;
|
|
char key_size_str[BEFORE_COLON];
|
|
|
|
p = buf;
|
|
n = size;
|
|
|
|
ret = mbedtls_snprintf( p, n, "%sCSR version : %d",
|
|
prefix, csr->version );
|
|
MBEDTLS_X509_SAFE_SNPRINTF;
|
|
|
|
ret = mbedtls_snprintf( p, n, "\n%ssubject name : ", prefix );
|
|
MBEDTLS_X509_SAFE_SNPRINTF;
|
|
ret = mbedtls_x509_dn_gets( p, n, &csr->subject );
|
|
MBEDTLS_X509_SAFE_SNPRINTF;
|
|
|
|
ret = mbedtls_snprintf( p, n, "\n%ssigned using : ", prefix );
|
|
MBEDTLS_X509_SAFE_SNPRINTF;
|
|
|
|
ret = mbedtls_x509_sig_alg_gets( p, n, &csr->sig_oid, csr->sig_pk, csr->sig_md,
|
|
csr->sig_opts );
|
|
MBEDTLS_X509_SAFE_SNPRINTF;
|
|
|
|
if( ( ret = mbedtls_x509_key_size_helper( key_size_str, BEFORE_COLON,
|
|
mbedtls_pk_get_name( &csr->pk ) ) ) != 0 )
|
|
{
|
|
return( ret );
|
|
}
|
|
|
|
ret = mbedtls_snprintf( p, n, "\n%s%-" BC "s: %d bits\n", prefix, key_size_str,
|
|
(int) mbedtls_pk_get_bitlen( &csr->pk ) );
|
|
MBEDTLS_X509_SAFE_SNPRINTF;
|
|
|
|
return( (int) ( size - n ) );
|
|
}
|
|
|
|
/*
|
|
* Initialize a CSR
|
|
*/
|
|
void mbedtls_x509_csr_init( mbedtls_x509_csr *csr )
|
|
{
|
|
memset( csr, 0, sizeof(mbedtls_x509_csr) );
|
|
}
|
|
|
|
/*
|
|
* Unallocate all CSR data
|
|
*/
|
|
void mbedtls_x509_csr_free( mbedtls_x509_csr *csr )
|
|
{
|
|
mbedtls_x509_name *name_cur;
|
|
mbedtls_x509_name *name_prv;
|
|
|
|
if( csr == NULL )
|
|
return;
|
|
|
|
mbedtls_pk_free( &csr->pk );
|
|
|
|
#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT)
|
|
mbedtls_free( csr->sig_opts );
|
|
#endif
|
|
|
|
name_cur = csr->subject.next;
|
|
while( name_cur != NULL )
|
|
{
|
|
name_prv = name_cur;
|
|
name_cur = name_cur->next;
|
|
mbedtls_platform_zeroize( name_prv, sizeof( mbedtls_x509_name ) );
|
|
mbedtls_free( name_prv );
|
|
}
|
|
|
|
if( csr->raw.p != NULL )
|
|
{
|
|
mbedtls_platform_zeroize( csr->raw.p, csr->raw.len );
|
|
mbedtls_free( csr->raw.p );
|
|
}
|
|
|
|
mbedtls_platform_zeroize( csr, sizeof( mbedtls_x509_csr ) );
|
|
}
|
|
|
|
#endif /* MBEDTLS_X509_CSR_PARSE_C */
|