[MBEDTLS] Update to version 2.16.10. CORE-17326
[reactos.git] / dll / 3rdparty / mbedtls / x509write_crt.c
index daebb81..5462e83 100644 (file)
@@ -62,6 +62,7 @@
 #include "mbedtls/oid.h"
 #include "mbedtls/asn1write.h"
 #include "mbedtls/sha1.h"
+#include "mbedtls/platform_util.h"
 
 #include <string.h>
 
 #include "mbedtls/pem.h"
 #endif /* MBEDTLS_PEM_WRITE_C */
 
-/* Implementation that should never be optimized out by the compiler */
-static void mbedtls_zeroize( void *v, size_t n ) {
-    volatile unsigned char *p = v; while( n-- ) *p++ = 0;
-}
-
 /*
  * For the currently used signature algorithms the buffer to store any signature
  * must be at least of size MAX(MBEDTLS_ECDSA_MAX_LEN, MBEDTLS_MPI_MAX_SIZE)
@@ -100,42 +96,47 @@ void mbedtls_x509write_crt_free( mbedtls_x509write_cert *ctx )
     mbedtls_asn1_free_named_data_list( &ctx->issuer );
     mbedtls_asn1_free_named_data_list( &ctx->extensions );
 
-    mbedtls_zeroize( ctx, sizeof( mbedtls_x509write_cert ) );
+    mbedtls_platform_zeroize( ctx, sizeof( mbedtls_x509write_cert ) );
 }
 
-void mbedtls_x509write_crt_set_version( mbedtls_x509write_cert *ctx, int version )
+void mbedtls_x509write_crt_set_version( mbedtls_x509write_cert *ctx,
+                                        int version )
 {
     ctx->version = version;
 }
 
-void mbedtls_x509write_crt_set_md_alg( mbedtls_x509write_cert *ctx, mbedtls_md_type_t md_alg )
+void mbedtls_x509write_crt_set_md_alg( mbedtls_x509write_cert *ctx,
+                                       mbedtls_md_type_t md_alg )
 {
     ctx->md_alg = md_alg;
 }
 
-void mbedtls_x509write_crt_set_subject_key( mbedtls_x509write_cert *ctx, mbedtls_pk_context *key )
+void mbedtls_x509write_crt_set_subject_key( mbedtls_x509write_cert *ctx,
+                                            mbedtls_pk_context *key )
 {
     ctx->subject_key = key;
 }
 
-void mbedtls_x509write_crt_set_issuer_key( mbedtls_x509write_cert *ctx, mbedtls_pk_context *key )
+void mbedtls_x509write_crt_set_issuer_key( mbedtls_x509write_cert *ctx,
+                                           mbedtls_pk_context *key )
 {
     ctx->issuer_key = key;
 }
 
 int mbedtls_x509write_crt_set_subject_name( mbedtls_x509write_cert *ctx,
-                                    const char *subject_name )
+                                            const char *subject_name )
 {
     return mbedtls_x509_string_to_names( &ctx->subject, subject_name );
 }
 
 int mbedtls_x509write_crt_set_issuer_name( mbedtls_x509write_cert *ctx,
-                                   const char *issuer_name )
+                                           const char *issuer_name )
 {
     return mbedtls_x509_string_to_names( &ctx->issuer, issuer_name );
 }
 
-int mbedtls_x509write_crt_set_serial( mbedtls_x509write_cert *ctx, const mbedtls_mpi *serial )
+int mbedtls_x509write_crt_set_serial( mbedtls_x509write_cert *ctx,
+                                      const mbedtls_mpi *serial )
 {
     int ret;
 
@@ -145,8 +146,9 @@ int mbedtls_x509write_crt_set_serial( mbedtls_x509write_cert *ctx, const mbedtls
     return( 0 );
 }
 
-int mbedtls_x509write_crt_set_validity( mbedtls_x509write_cert *ctx, const char *not_before,
-                                const char *not_after )
+int mbedtls_x509write_crt_set_validity( mbedtls_x509write_cert *ctx,
+                                        const char *not_before,
+                                        const char *not_after )
 {
     if( strlen( not_before ) != MBEDTLS_X509_RFC5280_UTC_TIME_LEN - 1 ||
         strlen( not_after )  != MBEDTLS_X509_RFC5280_UTC_TIME_LEN - 1 )
@@ -166,12 +168,12 @@ int mbedtls_x509write_crt_set_extension( mbedtls_x509write_cert *ctx,
                                  int critical,
                                  const unsigned char *val, size_t val_len )
 {
-    return mbedtls_x509_set_extension( &ctx->extensions, oid, oid_len,
-                               critical, val, val_len );
+    return( mbedtls_x509_set_extension( &ctx->extensions, oid, oid_len,
+                                        critical, val, val_len ) );
 }
 
 int mbedtls_x509write_crt_set_basic_constraints( mbedtls_x509write_cert *ctx,
-                                         int is_ca, int max_pathlen )
+                                                 int is_ca, int max_pathlen )
 {
     int ret;
     unsigned char buf[9];
@@ -187,18 +189,21 @@ int mbedtls_x509write_crt_set_basic_constraints( mbedtls_x509write_cert *ctx,
     {
         if( max_pathlen >= 0 )
         {
-            MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_int( &c, buf, max_pathlen ) );
+            MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_int( &c, buf,
+                                                               max_pathlen ) );
         }
         MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_bool( &c, buf, 1 ) );
     }
 
     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_CHK_ADD( len, mbedtls_asn1_write_tag( &c, buf,
+                                                MBEDTLS_ASN1_CONSTRUCTED |
                                                 MBEDTLS_ASN1_SEQUENCE ) );
 
-    return mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_BASIC_CONSTRAINTS,
-                                        MBEDTLS_OID_SIZE( MBEDTLS_OID_BASIC_CONSTRAINTS ),
-                                        0, buf + sizeof(buf) - len, len );
+    return(
+        mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_BASIC_CONSTRAINTS,
+                             MBEDTLS_OID_SIZE( MBEDTLS_OID_BASIC_CONSTRAINTS ),
+                             0, buf + sizeof(buf) - len, len ) );
 }
 
 #if defined(MBEDTLS_SHA1_C)
@@ -210,7 +215,8 @@ int mbedtls_x509write_crt_set_subject_key_identifier( mbedtls_x509write_cert *ct
     size_t len = 0;
 
     memset( buf, 0, sizeof(buf) );
-    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_pk_write_pubkey( &c, buf, ctx->subject_key ) );
+    MBEDTLS_ASN1_CHK_ADD( len,
+                mbedtls_pk_write_pubkey( &c, buf, ctx->subject_key ) );
 
     ret = mbedtls_sha1_ret( buf + sizeof( buf ) - len, len,
                             buf + sizeof( buf ) - 20 );
@@ -220,11 +226,13 @@ int mbedtls_x509write_crt_set_subject_key_identifier( mbedtls_x509write_cert *ct
     len = 20;
 
     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_OCTET_STRING ) );
+    MBEDTLS_ASN1_CHK_ADD( len,
+            mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_OCTET_STRING ) );
 
-    return mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_SUBJECT_KEY_IDENTIFIER,
-                                        MBEDTLS_OID_SIZE( MBEDTLS_OID_SUBJECT_KEY_IDENTIFIER ),
-                                        0, buf + sizeof(buf) - len, len );
+    return mbedtls_x509write_crt_set_extension( ctx,
+                 MBEDTLS_OID_SUBJECT_KEY_IDENTIFIER,
+                 MBEDTLS_OID_SIZE( MBEDTLS_OID_SUBJECT_KEY_IDENTIFIER ),
+                 0, buf + sizeof(buf) - len, len );
 }
 
 int mbedtls_x509write_crt_set_authority_key_identifier( mbedtls_x509write_cert *ctx )
@@ -235,7 +243,8 @@ int mbedtls_x509write_crt_set_authority_key_identifier( mbedtls_x509write_cert *
     size_t len = 0;
 
     memset( buf, 0, sizeof(buf) );
-    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_pk_write_pubkey( &c, buf, ctx->issuer_key ) );
+    MBEDTLS_ASN1_CHK_ADD( len,
+                          mbedtls_pk_write_pubkey( &c, buf, ctx->issuer_key ) );
 
     ret = mbedtls_sha1_ret( buf + sizeof( buf ) - len, len,
                             buf + sizeof( buf ) - 20 );
@@ -245,15 +254,19 @@ int mbedtls_x509write_crt_set_authority_key_identifier( mbedtls_x509write_cert *
     len = 20;
 
     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 | 0 ) );
+    MBEDTLS_ASN1_CHK_ADD( len,
+        mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_CONTEXT_SPECIFIC | 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 ) );
-
-    return mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_AUTHORITY_KEY_IDENTIFIER,
-                                   MBEDTLS_OID_SIZE( MBEDTLS_OID_AUTHORITY_KEY_IDENTIFIER ),
-                                   0, buf + sizeof( buf ) - len, len );
+    MBEDTLS_ASN1_CHK_ADD( len,
+                          mbedtls_asn1_write_tag( &c, buf,
+                                                  MBEDTLS_ASN1_CONSTRUCTED |
+                                                  MBEDTLS_ASN1_SEQUENCE ) );
+
+    return mbedtls_x509write_crt_set_extension(
+        ctx, MBEDTLS_OID_AUTHORITY_KEY_IDENTIFIER,
+        MBEDTLS_OID_SIZE( MBEDTLS_OID_AUTHORITY_KEY_IDENTIFIER ),
+        0, buf + sizeof( buf ) - len, len );
 }
 #endif /* MBEDTLS_SHA1_C */
 
@@ -300,8 +313,8 @@ int mbedtls_x509write_crt_set_key_usage( mbedtls_x509write_cert *ctx,
         return( MBEDTLS_ERR_X509_INVALID_FORMAT );
 
     ret = mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_KEY_USAGE,
-                                       MBEDTLS_OID_SIZE( MBEDTLS_OID_KEY_USAGE ),
-                                       1, c, (size_t)ret );
+                                   MBEDTLS_OID_SIZE( MBEDTLS_OID_KEY_USAGE ),
+                                   1, c, (size_t)ret );
     if( ret != 0 )
         return( ret );
 
@@ -327,8 +340,8 @@ int mbedtls_x509write_crt_set_ns_cert_type( mbedtls_x509write_cert *ctx,
         return( ret );
 
     ret = mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_NS_CERT_TYPE,
-                                       MBEDTLS_OID_SIZE( MBEDTLS_OID_NS_CERT_TYPE ),
-                                       0, c, (size_t)ret );
+                                   MBEDTLS_OID_SIZE( MBEDTLS_OID_NS_CERT_TYPE ),
+                                   0, c, (size_t)ret );
     if( ret != 0 )
         return( ret );
 
@@ -350,7 +363,8 @@ static int x509_write_time( unsigned char **p, unsigned char *start,
                                              (const unsigned char *) t + 2,
                                              size - 2 ) );
         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_UTC_TIME ) );
+        MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start,
+                                             MBEDTLS_ASN1_UTC_TIME ) );
     }
     else
     {
@@ -358,15 +372,17 @@ static int x509_write_time( unsigned char **p, unsigned char *start,
                                                   (const unsigned char *) t,
                                                   size ) );
         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_GENERALIZED_TIME ) );
+        MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start,
+                                             MBEDTLS_ASN1_GENERALIZED_TIME ) );
     }
 
     return( (int) len );
 }
 
-int mbedtls_x509write_crt_der( mbedtls_x509write_cert *ctx, unsigned char *buf, size_t size,
-                       int (*f_rng)(void *, unsigned char *, size_t),
-                       void *p_rng )
+int mbedtls_x509write_crt_der( mbedtls_x509write_cert *ctx,
+                               unsigned char *buf, size_t size,
+                               int (*f_rng)(void *, unsigned char *, size_t),
+                               void *p_rng )
 {
     int ret;
     const char *sig_oid;
@@ -374,15 +390,14 @@ int mbedtls_x509write_crt_der( mbedtls_x509write_cert *ctx, unsigned char *buf,
     unsigned char *c, *c2;
     unsigned char hash[64];
     unsigned char sig[SIGNATURE_MAX_SIZE];
-    unsigned char tmp_buf[2048];
     size_t sub_len = 0, pub_len = 0, sig_and_oid_len = 0, sig_len;
     size_t len = 0;
     mbedtls_pk_type_t pk_alg;
 
     /*
-     * Prepare data to be signed in tmp_buf
+     * Prepare data to be signed at the end of the target buffer
      */
-    c = tmp_buf + sizeof( tmp_buf );
+    c = buf + size;
 
     /* Signature algorithm needed in TBS, and later for actual signature */
 
@@ -408,27 +423,36 @@ int mbedtls_x509write_crt_der( mbedtls_x509write_cert *ctx, unsigned char *buf,
     /* Only for v3 */
     if( ctx->version == MBEDTLS_X509_CRT_VERSION_3 )
     {
-        MBEDTLS_ASN1_CHK_ADD( len, mbedtls_x509_write_extensions( &c, tmp_buf, ctx->extensions ) );
-        MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, len ) );
-        MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONSTRUCTED |
-                                                           MBEDTLS_ASN1_SEQUENCE ) );
-        MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, len ) );
-        MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONTEXT_SPECIFIC |
-                                                           MBEDTLS_ASN1_CONSTRUCTED | 3 ) );
+        MBEDTLS_ASN1_CHK_ADD( len,
+                              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 |
+                                               MBEDTLS_ASN1_CONSTRUCTED | 3 ) );
     }
 
     /*
      *  SubjectPublicKeyInfo
      */
-    MBEDTLS_ASN1_CHK_ADD( pub_len, mbedtls_pk_write_pubkey_der( ctx->subject_key,
-                                                tmp_buf, c - tmp_buf ) );
+    MBEDTLS_ASN1_CHK_ADD( pub_len,
+                          mbedtls_pk_write_pubkey_der( ctx->subject_key,
+                                                       buf, c - buf ) );
     c -= pub_len;
     len += pub_len;
 
     /*
      *  Subject  ::=  Name
      */
-    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_x509_write_names( &c, tmp_buf, ctx->subject ) );
+    MBEDTLS_ASN1_CHK_ADD( len,
+                          mbedtls_x509_write_names( &c, buf,
+                                                    ctx->subject ) );
 
     /*
      *  Validity ::= SEQUENCE {
@@ -437,32 +461,39 @@ int mbedtls_x509write_crt_der( mbedtls_x509write_cert *ctx, unsigned char *buf,
      */
     sub_len = 0;
 
-    MBEDTLS_ASN1_CHK_ADD( sub_len, x509_write_time( &c, tmp_buf, ctx->not_after,
-                                            MBEDTLS_X509_RFC5280_UTC_TIME_LEN ) );
+    MBEDTLS_ASN1_CHK_ADD( sub_len,
+                          x509_write_time( &c, buf, ctx->not_after,
+                                        MBEDTLS_X509_RFC5280_UTC_TIME_LEN ) );
 
-    MBEDTLS_ASN1_CHK_ADD( sub_len, x509_write_time( &c, tmp_buf, ctx->not_before,
-                                            MBEDTLS_X509_RFC5280_UTC_TIME_LEN ) );
+    MBEDTLS_ASN1_CHK_ADD( sub_len,
+                          x509_write_time( &c, buf, ctx->not_before,
+                                        MBEDTLS_X509_RFC5280_UTC_TIME_LEN ) );
 
     len += sub_len;
-    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, sub_len ) );
-    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONSTRUCTED |
-                                                    MBEDTLS_ASN1_SEQUENCE ) );
+    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, sub_len ) );
+    MBEDTLS_ASN1_CHK_ADD( len,
+                          mbedtls_asn1_write_tag( &c, buf,
+                                                  MBEDTLS_ASN1_CONSTRUCTED |
+                                                  MBEDTLS_ASN1_SEQUENCE ) );
 
     /*
      *  Issuer  ::=  Name
      */
-    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_x509_write_names( &c, tmp_buf, ctx->issuer ) );
+    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_x509_write_names( &c, buf,
+                                                         ctx->issuer ) );
 
     /*
      *  Signature   ::=  AlgorithmIdentifier
      */
-    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_algorithm_identifier( &c, tmp_buf,
-                       sig_oid, strlen( sig_oid ), 0 ) );
+    MBEDTLS_ASN1_CHK_ADD( len,
+                          mbedtls_asn1_write_algorithm_identifier( &c, buf,
+                                              sig_oid, strlen( sig_oid ), 0 ) );
 
     /*
      *  Serial   ::=  INTEGER
      */
-    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &c, tmp_buf, &ctx->serial ) );
+    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &c, buf,
+                                                       &ctx->serial ) );
 
     /*
      *  Version  ::=  INTEGER  {  v1(0), v2(1), v3(2)  }
@@ -472,48 +503,67 @@ int mbedtls_x509write_crt_der( mbedtls_x509write_cert *ctx, unsigned char *buf,
     if( ctx->version != MBEDTLS_X509_CRT_VERSION_1 )
     {
         sub_len = 0;
-        MBEDTLS_ASN1_CHK_ADD( sub_len, mbedtls_asn1_write_int( &c, tmp_buf, ctx->version ) );
+        MBEDTLS_ASN1_CHK_ADD( sub_len,
+                              mbedtls_asn1_write_int( &c, buf, ctx->version ) );
         len += sub_len;
-        MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, sub_len ) );
-        MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONTEXT_SPECIFIC |
-                                                           MBEDTLS_ASN1_CONSTRUCTED | 0 ) );
+        MBEDTLS_ASN1_CHK_ADD( len,
+                              mbedtls_asn1_write_len( &c, buf, sub_len ) );
+        MBEDTLS_ASN1_CHK_ADD( len,
+                              mbedtls_asn1_write_tag( &c, buf,
+                                               MBEDTLS_ASN1_CONTEXT_SPECIFIC |
+                                               MBEDTLS_ASN1_CONSTRUCTED | 0 ) );
     }
 
-    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, len ) );
-    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_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_SEQUENCE ) );
 
     /*
      * Make signature
      */
+
+    /* Compute hash of CRT. */
     if( ( ret = mbedtls_md( mbedtls_md_info_from_type( ctx->md_alg ), c,
                             len, hash ) ) != 0 )
     {
         return( ret );
     }
 
-    if( ( ret = mbedtls_pk_sign( ctx->issuer_key, ctx->md_alg, hash, 0, sig, &sig_len,
-                         f_rng, p_rng ) ) != 0 )
+    if( ( ret = mbedtls_pk_sign( ctx->issuer_key, ctx->md_alg,
+                                 hash, 0, sig, &sig_len,
+                                 f_rng, p_rng ) ) != 0 )
     {
         return( ret );
     }
 
-    /*
-     * Write data to output buffer
-     */
+    /* Move CRT to the front of the buffer to have space
+     * for the signature. */
+    memmove( buf, c, len );
+    c = buf + len;
+
+    /* Add signature at the end of the buffer,
+     * making sure that it doesn't underflow
+     * into the CRT buffer. */
     c2 = buf + size;
-    MBEDTLS_ASN1_CHK_ADD( sig_and_oid_len, mbedtls_x509_write_sig( &c2, buf,
+    MBEDTLS_ASN1_CHK_ADD( sig_and_oid_len, mbedtls_x509_write_sig( &c2, c,
                                         sig_oid, sig_oid_len, sig, sig_len ) );
 
-    if( len > (size_t)( c2 - buf ) )
-        return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
+    /*
+     * Memory layout after this step:
+     *
+     * buf       c=buf+len                c2            buf+size
+     * [CRT0,...,CRTn, UNUSED, ..., UNUSED, SIG0, ..., SIGm]
+     */
 
-    c2 -= len;
-    memcpy( c2, c, len );
+    /* Move raw CRT to just before the signature. */
+    c = c2 - len;
+    memmove( c, buf, len );
 
     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_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 ) );
 
     return( (int) len );
@@ -523,23 +573,23 @@ int mbedtls_x509write_crt_der( mbedtls_x509write_cert *ctx, unsigned char *buf,
 #define PEM_END_CRT             "-----END CERTIFICATE-----\n"
 
 #if defined(MBEDTLS_PEM_WRITE_C)
-int mbedtls_x509write_crt_pem( mbedtls_x509write_cert *crt, unsigned char *buf, size_t size,
-                       int (*f_rng)(void *, unsigned char *, size_t),
-                       void *p_rng )
+int mbedtls_x509write_crt_pem( mbedtls_x509write_cert *crt,
+                               unsigned char *buf, size_t size,
+                               int (*f_rng)(void *, unsigned char *, size_t),
+                               void *p_rng )
 {
     int ret;
-    unsigned char output_buf[4096];
-    size_t olen = 0;
+    size_t olen;
 
-    if( ( ret = mbedtls_x509write_crt_der( crt, output_buf, sizeof(output_buf),
+    if( ( ret = mbedtls_x509write_crt_der( crt, buf, size,
                                    f_rng, p_rng ) ) < 0 )
     {
         return( ret );
     }
 
     if( ( ret = mbedtls_pem_write_buffer( PEM_BEGIN_CRT, PEM_END_CRT,
-                                  output_buf + sizeof(output_buf) - ret,
-                                  ret, buf, size, &olen ) ) != 0 )
+                                          buf + size - ret, ret,
+                                          buf, size, &olen ) ) != 0 )
     {
         return( ret );
     }