]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[crypto] Construct signatures using ASN.1 builders
authorMichael Brown <mcb30@ipxe.org>
Mon, 1 Dec 2025 16:02:54 +0000 (16:02 +0000)
committerMichael Brown <mcb30@ipxe.org>
Mon, 1 Dec 2025 16:02:54 +0000 (16:02 +0000)
Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/crypto/crypto_null.c
src/crypto/rsa.c
src/drivers/net/iphone.c
src/include/ipxe/crypto.h
src/net/tls.c
src/tests/pubkey_test.c

index ca4e1b134c04ebc545cc47487913ea39d778eaa2..ee948e00d93d56f05bca7f9da6530a143bd5fec8 100644 (file)
@@ -113,7 +113,8 @@ int pubkey_null_decrypt ( const struct asn1_cursor *key __unused,
 
 int pubkey_null_sign ( const struct asn1_cursor *key __unused,
                       struct digest_algorithm *digest __unused,
-                      const void *value __unused, void *signature __unused ) {
+                      const void *value __unused,
+                      struct asn1_builder *signature __unused ) {
        return 0;
 }
 
index b93437518d5205dfadacf88ca1d5e8bca107572c..fd6a1ef395a02fdaf3a8fc3620de5fea1d79b037 100644 (file)
@@ -544,13 +544,12 @@ static int rsa_encode_digest ( struct rsa_context *context,
  * @v digest           Digest algorithm
  * @v value            Digest value
  * @v signature                Signature
- * @ret signature_len  Signature length, or negative error
+ * @ret rc             Return status code
  */
 static int rsa_sign ( const struct asn1_cursor *key,
                      struct digest_algorithm *digest, const void *value,
-                     void *signature ) {
+                     struct asn1_builder *signature ) {
        struct rsa_context context;
-       void *temp;
        int rc;
 
        DBGC ( &context, "RSA %p signing %s digest:\n",
@@ -561,24 +560,27 @@ static int rsa_sign ( const struct asn1_cursor *key,
        if ( ( rc = rsa_init ( &context, key ) ) != 0 )
                goto err_init;
 
-       /* Encode digest (using the big integer output buffer as
-        * temporary storage)
-        */
-       temp = context.output0;
-       if ( ( rc = rsa_encode_digest ( &context, digest, value, temp ) ) != 0 )
+       /* Create space for encoded digest and signature */
+       if ( ( rc = asn1_grow ( signature, context.max_len ) ) != 0 )
+               goto err_grow;
+
+       /* Encode digest */
+       if ( ( rc = rsa_encode_digest ( &context, digest, value,
+                                       signature->data ) ) != 0 )
                goto err_encode;
 
        /* Encipher the encoded digest */
-       rsa_cipher ( &context, temp, signature );
+       rsa_cipher ( &context, signature->data, signature->data );
        DBGC ( &context, "RSA %p signed %s digest:\n", &context, digest->name );
-       DBGC_HDA ( &context, 0, signature, context.max_len );
+       DBGC_HDA ( &context, 0, signature->data, signature->len );
 
        /* Free context */
        rsa_free ( &context );
 
-       return context.max_len;
+       return 0;
 
  err_encode:
+ err_grow:
        rsa_free ( &context );
  err_init:
        return rc;
index bcc9949fe48af6b021ffe0761ae20e0a96796f67..11f76355304b2e43f649071db2f62aacd3c83c11 100644 (file)
@@ -362,7 +362,6 @@ static int icert_cert ( struct icert *icert, struct asn1_cursor *subject,
        struct asn1_builder raw = { NULL, 0 };
        uint8_t digest_ctx[SHA256_CTX_SIZE];
        uint8_t digest_out[SHA256_DIGEST_SIZE];
-       int len;
        int rc;
 
        /* Construct subjectPublicKeyInfo */
@@ -399,20 +398,12 @@ static int icert_cert ( struct icert *icert, struct asn1_cursor *subject,
        digest_final ( digest, digest_ctx, digest_out );
 
        /* Construct signature using "private" key */
-       if ( ( rc = asn1_grow ( &raw,
-                               pubkey_max_len ( pubkey, private ) ) ) != 0 ) {
-               DBGC ( icert, "ICERT %p could not build signature: %s\n",
-                      icert, strerror ( rc ) );
-               goto err_grow;
-       }
-       if ( ( len = pubkey_sign ( pubkey, private, digest, digest_out,
-                                  raw.data ) ) < 0 ) {
-               rc = len;
+       if ( ( rc = pubkey_sign ( pubkey, private, digest, digest_out,
+                                 &raw ) ) != 0 ) {
                DBGC ( icert, "ICERT %p could not sign: %s\n",
                       icert, strerror ( rc ) );
                goto err_pubkey_sign;
        }
-       assert ( ( ( size_t ) len ) == raw.len );
 
        /* Construct raw certificate data */
        if ( ( rc = ( asn1_prepend_raw ( &raw, icert_nul,
@@ -438,12 +429,11 @@ static int icert_cert ( struct icert *icert, struct asn1_cursor *subject,
  err_x509:
  err_raw:
  err_pubkey_sign:
+ err_tbs:
+ err_spki:
        free ( raw.data );
- err_grow:
        free ( tbs.data );
- err_tbs:
        free ( spki.data );
- err_spki:
        return rc;
 }
 
index 5b87d1a47cad247e60667363f508ae255ccc719a..c457a74b11e3f3bc6a999b485b4e5ad7804cba7a 100644 (file)
@@ -153,11 +153,11 @@ struct pubkey_algorithm {
         * @v digest            Digest algorithm
         * @v value             Digest value
         * @v signature         Signature
-        * @ret signature_len   Signature length, or negative error
+        * @ret rc              Return status code
         */
        int ( * sign ) ( const struct asn1_cursor *key,
                         struct digest_algorithm *digest, const void *value,
-                        void *signature );
+                        struct asn1_builder *builder );
        /** Verify signed digest value
         *
         * @v key               Key
@@ -287,7 +287,7 @@ pubkey_decrypt ( struct pubkey_algorithm *pubkey, const struct asn1_cursor *key,
 static inline __attribute__ (( always_inline )) int
 pubkey_sign ( struct pubkey_algorithm *pubkey, const struct asn1_cursor *key,
              struct digest_algorithm *digest, const void *value,
-             void *signature ) {
+             struct asn1_builder *signature ) {
        return pubkey->sign ( key, digest, value, signature );
 }
 
@@ -332,7 +332,8 @@ extern int pubkey_null_decrypt ( const struct asn1_cursor *key,
                                 void *plaintext );
 extern int pubkey_null_sign ( const struct asn1_cursor *key,
                              struct digest_algorithm *digest,
-                             const void *value, void *signature );
+                             const void *value,
+                             struct asn1_builder *signature );
 extern int pubkey_null_verify ( const struct asn1_cursor *key,
                                struct digest_algorithm *digest,
                                const void *value,
index 1bcb5c027e73f9fd42a1c6f83fbceb7b1f36773b..c01ce9515489a6854479c1c90f7c3d9d8756e6cf 100644 (file)
@@ -1863,6 +1863,7 @@ static int tls_send_certificate_verify ( struct tls_connection *tls ) {
        struct asn1_cursor *key = privkey_cursor ( tls->client.key );
        uint8_t digest_out[ digest->digestsize ];
        struct tls_signature_hash_algorithm *sig_hash = NULL;
+       struct asn1_builder builder = { NULL, 0 };
        int rc;
 
        /* Generate digest to be signed */
@@ -1880,53 +1881,53 @@ static int tls_send_certificate_verify ( struct tls_connection *tls ) {
                }
        }
 
-       /* Generate and transmit record */
+       /* Sign digest */
+       if ( ( rc = pubkey_sign ( pubkey, key, digest, digest_out,
+                                 &builder ) ) != 0 ) {
+               DBGC ( tls, "TLS %p could not sign %s digest using %s client "
+                      "private key: %s\n", tls, digest->name, pubkey->name,
+                      strerror ( rc ) );
+               goto err_pubkey_sign;
+       }
+
+       /* Construct Certificate Verify record */
        {
-               size_t max_len = pubkey_max_len ( pubkey, key );
                int use_sig_hash = ( ( sig_hash == NULL ) ? 0 : 1 );
                struct {
                        uint32_t type_length;
                        struct tls_signature_hash_id sig_hash[use_sig_hash];
                        uint16_t signature_len;
-                       uint8_t signature[max_len];
-               } __attribute__ (( packed )) certificate_verify;
-               size_t unused;
-               int len;
-
-               /* Sign digest */
-               len = pubkey_sign ( pubkey, key, digest, digest_out,
-                                   certificate_verify.signature );
-               if ( len < 0 ) {
-                       rc = len;
-                       DBGC ( tls, "TLS %p could not sign %s digest using %s "
-                              "client private key: %s\n", tls, digest->name,
-                              pubkey->name, strerror ( rc ) );
-                       goto err_pubkey_sign;
-               }
-               unused = ( max_len - len );
-
-               /* Construct Certificate Verify record */
-               certificate_verify.type_length =
-                       ( cpu_to_le32 ( TLS_CERTIFICATE_VERIFY ) |
-                         htonl ( sizeof ( certificate_verify ) -
-                                 sizeof ( certificate_verify.type_length ) -
-                                 unused ) );
+               } __attribute__ (( packed )) header;
+
+               header.type_length = ( cpu_to_le32 ( TLS_CERTIFICATE_VERIFY ) |
+                                      htonl ( builder.len +
+                                              sizeof ( header ) -
+                                              sizeof ( header.type_length )));
                if ( use_sig_hash ) {
-                       memcpy ( &certificate_verify.sig_hash[0],
-                                &sig_hash->code,
-                                sizeof ( certificate_verify.sig_hash[0] ) );
+                       memcpy ( &header.sig_hash[0], &sig_hash->code,
+                                sizeof ( header.sig_hash[0] ) );
                }
-               certificate_verify.signature_len =
-                       htons ( sizeof ( certificate_verify.signature ) -
-                               unused );
+               header.signature_len = htons ( builder.len );
 
-               /* Transmit record */
-               rc = tls_send_handshake ( tls, &certificate_verify,
-                                  ( sizeof ( certificate_verify ) - unused ) );
+               if ( ( rc = asn1_prepend_raw ( &builder, &header,
+                                              sizeof ( header ) ) ) != 0 ) {
+                       DBGC ( tls, "TLS %p could not construct Certificate "
+                              "Verify: %s\n", tls, strerror ( rc ) );
+                       goto err_prepend;
+               }
+       }
+
+       /* Transmit record */
+       if ( ( rc = tls_send_handshake ( tls, builder.data,
+                                        builder.len ) ) != 0 ) {
+               goto err_send;
        }
 
+ err_send:
+ err_prepend:
  err_pubkey_sign:
  err_sig_hash:
+       free ( builder.data );
        return rc;
 }
 
index 2e0eeb116e9e9da933145017982f8b10a013b2d7..e3fbc3b3f530e85f79fb392325cff5d98ec546e5 100644 (file)
@@ -98,13 +98,10 @@ void pubkey_sign_okx ( struct pubkey_sign_test *test, const char *file,
                       unsigned int line ) {
        struct pubkey_algorithm *pubkey = test->pubkey;
        struct digest_algorithm *digest = test->digest;
-       size_t max_len = pubkey_max_len ( pubkey, &test->private );
-       uint8_t bad[test->signature.len];
        uint8_t digestctx[digest->ctxsize ];
        uint8_t digestout[digest->digestsize];
-       uint8_t signature[max_len];
-       struct asn1_cursor cursor;
-       int signature_len;
+       struct asn1_builder signature = { NULL, 0 };
+       uint8_t *bad;
 
        /* Construct digest over plaintext */
        digest_init ( digest, digestctx );
@@ -113,21 +110,24 @@ void pubkey_sign_okx ( struct pubkey_sign_test *test, const char *file,
        digest_final ( digest, digestctx, digestout );
 
        /* Test signing using private key */
-       signature_len = pubkey_sign ( pubkey, &test->private, digest,
-                                     digestout, signature );
-       okx ( signature_len == ( ( int ) test->signature.len ), file, line );
-       okx ( memcmp ( signature, test->signature.data,
-                      test->signature.len ) == 0, file, line );
+       okx ( pubkey_sign ( pubkey, &test->private, digest, digestout,
+                           &signature ) == 0, file, line );
+       okx ( signature.len != 0, file, line );
+       okx ( asn1_compare ( asn1_built ( &signature ),
+                            &test->signature ) == 0, file, line );
 
        /* Test verification using public key */
        okx ( pubkey_verify ( pubkey, &test->public, digest, digestout,
                              &test->signature ) == 0, file, line );
 
        /* Test verification failure of modified signature */
-       memcpy ( bad, test->signature.data, test->signature.len );
-       bad[ test->signature.len / 2 ] ^= 0x40;
-       cursor.data = bad;
-       cursor.len = test->signature.len;
+       bad = ( signature.data + ( test->signature.len / 2 ) );
+       okx ( pubkey_verify ( pubkey, &test->public, digest, digestout,
+                             asn1_built ( &signature ) ) == 0, file, line );
+       *bad ^= 0x40;
        okx ( pubkey_verify ( pubkey, &test->public, digest, digestout,
-                             &cursor ) != 0, file, line );
+                             asn1_built ( &signature ) ) != 0, file, line );
+
+       /* Free signature */
+       free ( signature.data );
 }