]> www.infradead.org Git - users/dwmw2/openconnect.git/commitdiff
Tell TPMv2 the hash type based on size
authorDavid Woodhouse <dwmw2@infradead.org>
Tue, 11 May 2021 20:49:33 +0000 (21:49 +0100)
committerDavid Woodhouse <dwmw2@infradead.org>
Tue, 11 May 2021 22:33:58 +0000 (23:33 +0100)
The TPM doesn't really have any business knowing this, and the only thing
that matters is the size. Which is truncated to the curve bit length even
for larger hashes.

Signed-off-by: David Woodhouse <dwmw2@infradead.org>
gnutls_tpm2.c
gnutls_tpm2_esys.c
gnutls_tpm2_ibm.c
openconnect-internal.h

index 467cd1d189ded071175abfedb52066c7938a2ec5..a3ba3cdb4a64107191261e5d9071fdf41a968a6c 100644 (file)
@@ -84,10 +84,10 @@ static int tpm2_ec_sign_fn(gnutls_privkey_t key, void *_certinfo,
        gnutls_sign_algorithm_t algo;
 
        switch (data->size) {
-       case 20: algo = GNUTLS_SIGN_ECDSA_SHA1; break;
-       case 32: algo = GNUTLS_SIGN_ECDSA_SHA256; break;
-       case 48: algo = GNUTLS_SIGN_ECDSA_SHA384; break;
-       case 64: algo = GNUTLS_SIGN_ECDSA_SHA512; break;
+       case SHA1_SIZE:   algo = GNUTLS_SIGN_ECDSA_SHA1; break;
+       case SHA256_SIZE: algo = GNUTLS_SIGN_ECDSA_SHA256; break;
+       case SHA384_SIZE: algo = GNUTLS_SIGN_ECDSA_SHA384; break;
+       case SHA512_SIZE: algo = GNUTLS_SIGN_ECDSA_SHA512; break;
        default:
                vpn_progress(vpninfo, PRG_ERR,
                             _("Unknown TPM2 EC digest size %d\n"),
index f462222fe9e1315e39116dec14a833d5670d700c..a57b843f56f7368147ced42ce1ec9c62c542bb1c 100644 (file)
@@ -482,15 +482,25 @@ int tpm2_ec_sign_hash_fn(gnutls_privkey_t key, gnutls_sign_algorithm_t algo,
                     _("TPM2 EC sign function called for %d bytes.\n"),
                     data->size);
 
-       switch (algo) {
-       case GNUTLS_SIGN_ECDSA_SHA1:   inScheme.details.ecdsa.hashAlg = TPM2_ALG_SHA1;   break;
-       case GNUTLS_SIGN_ECDSA_SHA256: inScheme.details.ecdsa.hashAlg = TPM2_ALG_SHA256; break;
-       case GNUTLS_SIGN_ECDSA_SHA384: inScheme.details.ecdsa.hashAlg = TPM2_ALG_SHA384; break;
-       case GNUTLS_SIGN_ECDSA_SHA512: inScheme.details.ecdsa.hashAlg = TPM2_ALG_SHA512; break;
+       /* FIPS-186-4 §6.4 says "When the length of the output of the hash
+        * function is greater than the bit length of n, then the leftmost
+        * n bits of the hash function output block shall be used in any
+        * calculation using the hash function output during the generation
+        * or verification of a digital signature."
+        *
+        * So GnuTLS is expected to *truncate* a larger hash to fit the
+        * curve bit length, and then we lie to the TPM about which hash
+        * it was because the TPM only really cares about the size of the
+        * data anyway. */
+       switch (data->size) {
+       case SHA1_SIZE:   inScheme.details.ecdsa.hashAlg = TPM2_ALG_SHA1;   break;
+       case SHA256_SIZE: inScheme.details.ecdsa.hashAlg = TPM2_ALG_SHA256; break;
+       case SHA384_SIZE: inScheme.details.ecdsa.hashAlg = TPM2_ALG_SHA384; break;
+       case SHA512_SIZE: inScheme.details.ecdsa.hashAlg = TPM2_ALG_SHA512; break;
        default:
                vpn_progress(vpninfo, PRG_ERR,
-                            _("Unknown TPM2 EC digest size %d\n"),
-                            data->size);
+                            _("Unknown TPM2 EC digest size %d for algo 0x%x\n"),
+                            data->size, algo);
                return GNUTLS_E_PK_SIGN_FAILED;
        }
 
index 0232e3145fb0db22ea8f46e5be93c10a3c73824c..fdf6fe56b004383512fc1857d6a307d41d94c95a 100644 (file)
@@ -420,17 +420,28 @@ int tpm2_ec_sign_hash_fn(gnutls_privkey_t key, gnutls_sign_algorithm_t algo,
 
        memset(&in, 0, sizeof(in));
 
-       switch (algo) {
-       case GNUTLS_SIGN_ECDSA_SHA1:   in.inScheme.details.ecdsa.hashAlg = TPM_ALG_SHA1;   break;
-       case GNUTLS_SIGN_ECDSA_SHA256: in.inScheme.details.ecdsa.hashAlg = TPM_ALG_SHA256; break;
-       case GNUTLS_SIGN_ECDSA_SHA384: in.inScheme.details.ecdsa.hashAlg = TPM_ALG_SHA384; break;
+
+       /* FIPS-186-4 §6.4 says "When the length of the output of the hash
+        * function is greater than the bit length of n, then the leftmost
+        * n bits of the hash function output block shall be used in any
+        * calculation using the hash function output during the generation
+        * or verification of a digital signature."
+        *
+        * So GnuTLS is expected to *truncate* a larger hash to fit the
+        * curve bit length, and then we lie to the TPM about which hash
+        * it was because the TPM only really cares about the size of the
+        * data anyway. */
+       switch (data->size) {
+       case SHA1_SIZE:   in.inScheme.details.ecdsa.hashAlg = TPM_ALG_SHA1;   break;
+       case SHA256_SIZE: in.inScheme.details.ecdsa.hashAlg = TPM_ALG_SHA256; break;
+       case SHA384_SIZE: in.inScheme.details.ecdsa.hashAlg = TPM_ALG_SHA384; break;
 #ifdef TPM_ALG_SHA512
-       case GNUTLS_SIGN_ECDSA_SHA512: in.inScheme.details.ecdsa.hashAlg = TPM_ALG_SHA512; break;
+       case SHA512_SIZE: in.inScheme.details.ecdsa.hashAlg = TPM_ALG_SHA512; break;
 #endif
        default:
                vpn_progress(vpninfo, PRG_ERR,
-                            _("Unknown TPM2 EC digest size %d\n"),
-                            data->size);
+                            _("Unknown TPM2 EC digest size %d for algo 0x%x\n"),
+                            data->size, algo);
                return GNUTLS_E_PK_SIGN_FAILED;
        }
 
index 5869ec8a8f313db105ca609ed0050556bdecd200..1ba62fbd42d5007d189f50ec57e4e5eeb99a17fd 100644 (file)
 
 #include <json.h>
 
+#define SHA512_SIZE 64
+#define SHA384_SIZE 48
 #define SHA256_SIZE 32
 #define SHA1_SIZE 20
 #define MD5_SIZE 16