Subdivide rsa_rsassa_pkcs1_v15_encode

Split the DigestInfo construction and the initial padding out of
rsa_rsassa_pkcs1_v15_encode into their own functions.
diff --git a/library/rsa.c b/library/rsa.c
index 8c0d8c3..9e4a213 100644
--- a/library/rsa.c
+++ b/library/rsa.c
@@ -1523,6 +1523,112 @@
  * Implementation of the PKCS#1 v2.1 RSASSA-PKCS1-V1_5-SIGN function
  */
 
+/* Encode a hash into a DigestInfo structure as specified by PKCS#1
+ * (RFC 8017, EMSA-PKCS1-v1_5-ENCODE step 2).
+ * Write to the left of p and set *p to the leftmost byte written. */
+static int rsa_emsa_pkcs1_v15_encode_digestinfo( unsigned char **p,
+                                                 unsigned char *start,
+                                                 mbedtls_md_type_t md_alg,
+                                                 const unsigned char *hash,
+                                                 size_t hashlen )
+{
+    const mbedtls_md_info_t *md_info;
+    const char *oid;
+    size_t oid_size;
+
+    if( md_alg == MBEDTLS_MD_NONE )
+    {
+        if( *p < start + hashlen )
+            return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
+        *p -= hashlen;
+        memcpy( *p, hash, hashlen );
+        return( 0 );
+    }
+
+    md_info = mbedtls_md_info_from_type( md_alg );
+    if( md_info == NULL )
+        return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
+    if( hashlen == 0 )
+        hashlen = mbedtls_md_get_size( md_info );
+    else if ( hashlen != mbedtls_md_get_size( md_info ) )
+        return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
+    if( mbedtls_oid_get_oid_by_md( md_alg, &oid, &oid_size ) != 0 )
+        return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
+
+    /* Double-check that 8 + hashlen + oid_size can be used as a
+     * 1-byte ASN.1 length encoding and that there's no overflow. */
+    if( 8 + hashlen + oid_size  >= 0x80         ||
+        10 + hashlen            <  hashlen      ||
+        10 + hashlen + oid_size <  10 + hashlen )
+        return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
+
+    /*
+     * Static bounds check:
+     * - Need 10 bytes for five tag-length pairs.
+     *   (Insist on 1-byte length encodings to protect against variants of
+     *    Bleichenbacher's forgery attack against lax PKCS#1v1.5 verification)
+     * - Need hashlen bytes for hash
+     * - Need oid_size bytes for hash alg OID.
+     */
+    if( *p < start + 10 + oid_size + hashlen )
+        return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
+    *p -= 10 + oid_size + hashlen;
+    start = *p;
+
+    /* Signing hashed data, add corresponding ASN.1 structure
+     *
+     * DigestInfo ::= SEQUENCE {
+     *   digestAlgorithm DigestAlgorithmIdentifier,
+     *   digest Digest }
+     * DigestAlgorithmIdentifier ::= AlgorithmIdentifier
+     * Digest ::= OCTET STRING
+     *
+     * Schematic:
+     * TAG-SEQ + LEN [ TAG-SEQ + LEN [ TAG-OID  + LEN [ OID  ]
+     *                                 TAG-NULL + LEN [ NULL ] ]
+     *                 TAG-OCTET + LEN [ HASH ] ]
+     */
+    *start++ = MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED;
+    *start++ = (unsigned char)( 0x08 + oid_size + hashlen );
+    *start++ = MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED;
+    *start++ = (unsigned char)( 0x04 + oid_size );
+    *start++ = MBEDTLS_ASN1_OID;
+    *start++ = (unsigned char) oid_size;
+    memcpy( start, oid, oid_size );
+    start += oid_size;
+    *start++ = MBEDTLS_ASN1_NULL;
+    *start++ = 0x00;
+    *start++ = MBEDTLS_ASN1_OCTET_STRING;
+    *start++ = (unsigned char) hashlen;
+    memcpy( start, hash, hashlen );
+    start += hashlen;
+    return( 0 );
+}
+
+/* Pad data as specified by PKCS#1
+ * (RFC 8017, EMSA-PKCS1-v1_5-ENCODE steps 3-5 without T). */
+static int rsa_rsassa_pkcs1_v15_encode_pad( unsigned char *p,
+                                            size_t nb_pad )
+{
+    /* Need space for signature header and padding delimiter (3 bytes),
+     * and 8 bytes for the minimal padding */
+    if( nb_pad < 3 + 8 )
+        return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
+    nb_pad -= 3;
+
+    /* Now nb_pad is the amount of memory to be filled
+     * with padding, and at least 8 bytes long. */
+
+    /* Write signature header and padding */
+    *p++ = 0;
+    *p++ = MBEDTLS_RSA_SIGN;
+    memset( p, 0xFF, nb_pad );
+    p += nb_pad;
+    *p++ = 0;
+
+    return( 0 );
+}
+
 /* Construct a PKCS v1.5 encoding of a hashed message
  *
  * This is used both for signature generation and verification.
@@ -1547,107 +1653,24 @@
                                         size_t dst_len,
                                         unsigned char *dst )
 {
-    size_t oid_size  = 0;
-    size_t nb_pad    = dst_len;
-    unsigned char *p = dst;
-    const char *oid  = NULL;
+    int ret;
+    unsigned char *p = dst + dst_len;
 
-    /* Are we signing hashed or raw data? */
+    /* Ignore hashlen if a hash algorithm is specified. This is
+     * fragile, but documented, bhavior. */
     if( md_alg != MBEDTLS_MD_NONE )
+        hashlen = 0;
+
+    ret = rsa_emsa_pkcs1_v15_encode_digestinfo( &p, dst,
+                                                md_alg, hash, hashlen );
+    if( ret != 0 )
+        return( ret );
+
+    ret = rsa_rsassa_pkcs1_v15_encode_pad( dst, p - dst );
+    if( ret != 0 )
     {
-        const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type( md_alg );
-        if( md_info == NULL )
-            return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
-
-        if( mbedtls_oid_get_oid_by_md( md_alg, &oid, &oid_size ) != 0 )
-            return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
-
-        hashlen = mbedtls_md_get_size( md_info );
-
-        /* Double-check that 8 + hashlen + oid_size can be used as a
-         * 1-byte ASN.1 length encoding and that there's no overflow. */
-        if( 8 + hashlen + oid_size  >= 0x80         ||
-            10 + hashlen            <  hashlen      ||
-            10 + hashlen + oid_size <  10 + hashlen )
-            return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
-
-        /*
-         * Static bounds check:
-         * - Need 10 bytes for five tag-length pairs.
-         *   (Insist on 1-byte length encodings to protect against variants of
-         *    Bleichenbacher's forgery attack against lax PKCS#1v1.5 verification)
-         * - Need hashlen bytes for hash
-         * - Need oid_size bytes for hash alg OID.
-         */
-        if( nb_pad < 10 + hashlen + oid_size )
-            return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
-        nb_pad -= 10 + hashlen + oid_size;
-    }
-    else
-    {
-        if( nb_pad < hashlen )
-            return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
-
-        nb_pad -= hashlen;
-    }
-
-    /* Need space for signature header and padding delimiter (3 bytes),
-     * and 8 bytes for the minimal padding */
-    if( nb_pad < 3 + 8 )
-        return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
-    nb_pad -= 3;
-
-    /* Now nb_pad is the amount of memory to be filled
-     * with padding, and at least 8 bytes long. */
-
-    /* Write signature header and padding */
-    *p++ = 0;
-    *p++ = MBEDTLS_RSA_SIGN;
-    memset( p, 0xFF, nb_pad );
-    p += nb_pad;
-    *p++ = 0;
-
-    /* Are we signing raw data? */
-    if( md_alg == MBEDTLS_MD_NONE )
-    {
-        memcpy( p, hash, hashlen );
-        return( 0 );
-    }
-
-    /* Signing hashed data, add corresponding ASN.1 structure
-     *
-     * DigestInfo ::= SEQUENCE {
-     *   digestAlgorithm DigestAlgorithmIdentifier,
-     *   digest Digest }
-     * DigestAlgorithmIdentifier ::= AlgorithmIdentifier
-     * Digest ::= OCTET STRING
-     *
-     * Schematic:
-     * TAG-SEQ + LEN [ TAG-SEQ + LEN [ TAG-OID  + LEN [ OID  ]
-     *                                 TAG-NULL + LEN [ NULL ] ]
-     *                 TAG-OCTET + LEN [ HASH ] ]
-     */
-    *p++ = MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED;
-    *p++ = (unsigned char)( 0x08 + oid_size + hashlen );
-    *p++ = MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED;
-    *p++ = (unsigned char)( 0x04 + oid_size );
-    *p++ = MBEDTLS_ASN1_OID;
-    *p++ = (unsigned char) oid_size;
-    memcpy( p, oid, oid_size );
-    p += oid_size;
-    *p++ = MBEDTLS_ASN1_NULL;
-    *p++ = 0x00;
-    *p++ = MBEDTLS_ASN1_OCTET_STRING;
-    *p++ = (unsigned char) hashlen;
-    memcpy( p, hash, hashlen );
-    p += hashlen;
-
-    /* Just a sanity-check, should be automatic
-     * after the initial bounds check. */
-    if( p != dst + dst_len )
-    {
-        mbedtls_zeroize( dst, dst_len );
-        return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
+        memset( dst, 0, dst_len );
+        return( ret );
     }
 
     return( 0 );