Skip to content

Commit

Permalink
Clean up COSE to hash algorithm map
Browse files Browse the repository at this point in the history
  • Loading branch information
aseigler committed Aug 11, 2020
1 parent 1c80ae0 commit 7305982
Show file tree
Hide file tree
Showing 10 changed files with 140 additions and 297 deletions.
6 changes: 3 additions & 3 deletions Src/Fido2/AttestationFormat/AndroidKey.cs
@@ -1,9 +1,9 @@
using System;
using System.Diagnostics;
using System.Linq;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using Asn1;
using Fido2NetLib.Objects;
using PeterO.Cbor;

namespace Fido2NetLib.AttestationFormat
Expand Down Expand Up @@ -170,7 +170,7 @@ public override void Verify()
throw new Fido2VerificationException("Failed to extract public key from android key: " + ex.Message, ex);
}

if (null == Alg || true != Alg.IsNumber || false == CryptoUtils.algMap.ContainsKey(Alg.AsInt32()))
if (null == Alg || true != Alg.IsNumber)
throw new Fido2VerificationException("Invalid android key attestation algorithm");

byte[] ecsig;
Expand All @@ -183,7 +183,7 @@ public override void Verify()
throw new Fido2VerificationException("Failed to decode android key attestation signature from ASN.1 encoded form", ex);
}

if (true != androidKeyPubKey.VerifyData(Data, ecsig, CryptoUtils.algMap[Alg.AsInt32()]))
if (true != androidKeyPubKey.VerifyData(Data, ecsig, CryptoUtils.HashAlgFromCOSEAlg(Alg.AsInt32())))
throw new Fido2VerificationException("Invalid android key attestation signature");

// 3. Verify that the public key in the first certificate in x5c matches the credentialPublicKey in the attestedCredentialData in authenticatorData.
Expand Down
2 changes: 1 addition & 1 deletion Src/Fido2/AttestationFormat/FidoU2f.cs
Expand Up @@ -91,7 +91,7 @@ public override void Verify()
}

var coseAlg = CredentialPublicKey[CBORObject.FromObject(COSE.KeyCommonParameter.Alg)].AsInt32();
var hashAlg = CryptoUtils.algMap[coseAlg];
var hashAlg = CryptoUtils.HashAlgFromCOSEAlg(coseAlg);

if (true != pubKey.VerifyData(verificationData, ecsig, hashAlg))
throw new Fido2VerificationException("Invalid fido-u2f attestation signature");
Expand Down
4 changes: 0 additions & 4 deletions Src/Fido2/AttestationFormat/Packed.cs
Expand Up @@ -83,10 +83,6 @@ public override void Verify()

// 2a. Verify that sig is a valid signature over the concatenation of authenticatorData and clientDataHash
// using the attestation public key in attestnCert with the algorithm specified in alg
var packedPubKey = attestnCert.GetECDsaPublicKey(); // attestation public key
if (false == CryptoUtils.algMap.ContainsKey(Alg.AsInt32()))
throw new Fido2VerificationException("Invalid attestation algorithm");

var cpk = new CredentialPublicKey(attestnCert, Alg.AsInt32());
if (true != cpk.Verify(Data, Sig.GetByteString()))
throw new Fido2VerificationException("Invalid full packed signature");
Expand Down
6 changes: 3 additions & 3 deletions Src/Fido2/AttestationFormat/Tpm.cs
Expand Up @@ -116,17 +116,17 @@ public override void Verify()
// Handled in CertInfo constructor, see CertInfo.Type

// 4c. Verify that extraData is set to the hash of attToBeSigned using the hash algorithm employed in "alg"
if (null == Alg || true != Alg.IsNumber || false == CryptoUtils.algMap.ContainsKey(Alg.AsInt32()))
if (null == Alg || true != Alg.IsNumber)
throw new Fido2VerificationException("Invalid TPM attestation algorithm");

using(var hasher = CryptoUtils.GetHasher(CryptoUtils.algMap[Alg.AsInt32()]))
using(var hasher = CryptoUtils.GetHasher(CryptoUtils.HashAlgFromCOSEAlg(Alg.AsInt32())))
{
if (!hasher.ComputeHash(Data).SequenceEqual(certInfo.ExtraData))
throw new Fido2VerificationException("Hash value mismatch extraData and attToBeSigned");
}

// 4d. Verify that attested contains a TPMS_CERTIFY_INFO structure, whose name field contains a valid Name for pubArea, as computed using the algorithm in the nameAlg field of pubArea
using(var hasher = CryptoUtils.GetHasher(CryptoUtils.algMap[certInfo.Alg]))
using(var hasher = CryptoUtils.GetHasher(CryptoUtils.HashAlgFromCOSEAlg(certInfo.Alg)))
{
if (false == hasher.ComputeHash(pubArea.Raw).SequenceEqual(certInfo.AttestedName))
throw new Fido2VerificationException("Hash value mismatch attested and pubArea");
Expand Down
39 changes: 21 additions & 18 deletions Src/Fido2/CryptoUtils.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
Expand Down Expand Up @@ -40,24 +39,28 @@ public static HashAlgorithm GetHasher(HashAlgorithmName hashName)
}
}

public static readonly Dictionary<int, HashAlgorithmName> algMap = new Dictionary<int, HashAlgorithmName>
public static HashAlgorithmName HashAlgFromCOSEAlg(int alg)
{
{(int) COSE.Algorithm.RS1, HashAlgorithmName.SHA1 },
{(int) COSE.Algorithm.ES256, HashAlgorithmName.SHA256},
{(int) COSE.Algorithm.ES384, HashAlgorithmName.SHA384 },
{(int) COSE.Algorithm.ES512, HashAlgorithmName.SHA512 },
{(int) COSE.Algorithm.PS256, HashAlgorithmName.SHA256 },
{(int) COSE.Algorithm.PS384, HashAlgorithmName.SHA384 },
{(int) COSE.Algorithm.PS512, HashAlgorithmName.SHA512 },
{(int) COSE.Algorithm.RS256, HashAlgorithmName.SHA256 },
{(int) COSE.Algorithm.RS384, HashAlgorithmName.SHA384 },
{(int) COSE.Algorithm.RS512, HashAlgorithmName.SHA512 },
{4, HashAlgorithmName.SHA1 },
{11, HashAlgorithmName.SHA256 },
{12, HashAlgorithmName.SHA384 },
{13, HashAlgorithmName.SHA512 },
{(int) COSE.Algorithm.EdDSA, HashAlgorithmName.SHA512 }
};
return (COSE.Algorithm)alg switch
{
COSE.Algorithm.RS1 => HashAlgorithmName.SHA1,
COSE.Algorithm.ES256 => HashAlgorithmName.SHA256,
COSE.Algorithm.ES384 => HashAlgorithmName.SHA384,
COSE.Algorithm.ES512 => HashAlgorithmName.SHA512,
COSE.Algorithm.PS256 => HashAlgorithmName.SHA256,
COSE.Algorithm.PS384 => HashAlgorithmName.SHA384,
COSE.Algorithm.PS512 => HashAlgorithmName.SHA512,
COSE.Algorithm.RS256 => HashAlgorithmName.SHA256,
COSE.Algorithm.RS384 => HashAlgorithmName.SHA384,
COSE.Algorithm.RS512 => HashAlgorithmName.SHA512,
(COSE.Algorithm)4 => HashAlgorithmName.SHA1,
(COSE.Algorithm)11 => HashAlgorithmName.SHA256,
(COSE.Algorithm)12 => HashAlgorithmName.SHA384,
(COSE.Algorithm)13 => HashAlgorithmName.SHA512,
COSE.Algorithm.EdDSA => HashAlgorithmName.SHA512,
_ => throw new Fido2VerificationException("Unrecognized COSE alg value"),
};
}

public static byte[] SigFromEcDsaSig(byte[] ecDsaSig, int keySize)
{
Expand Down
4 changes: 2 additions & 2 deletions Src/Fido2/Objects/CredentialPublicKey.cs
Expand Up @@ -84,13 +84,13 @@ public bool Verify(byte[] data, byte[] sig)
using(ECDsa ecdsa = CreateECDsa())
{
var ecsig = CryptoUtils.SigFromEcDsaSig(sig, ecdsa.KeySize);
return ecdsa.VerifyData(data, ecsig, CryptoUtils.algMap[(int)_alg]);
return ecdsa.VerifyData(data, ecsig, CryptoUtils.HashAlgFromCOSEAlg((int)_alg));
}

case COSE.KeyType.RSA:
using (RSA rsa = CreateRsa())
{
return rsa.VerifyData(data, sig, CryptoUtils.algMap[(int)_alg], Padding);
return rsa.VerifyData(data, sig, CryptoUtils.HashAlgFromCOSEAlg((int)_alg), Padding);
}

case COSE.KeyType.OKP:
Expand Down
2 changes: 1 addition & 1 deletion Test/Attestation/AndroidKey.cs
Expand Up @@ -175,7 +175,7 @@ public void TestAndroidKeyAlgNotInMap()
{
_attestationObject["attStmt"].Set("alg", -1);
var ex = Assert.ThrowsAsync<Fido2VerificationException>(() => MakeAttestationResponse());
Assert.Equal("Invalid android key attestation algorithm", ex.Result.Message);
Assert.Equal("Unrecognized COSE alg value", ex.Result.Message);
}

[Fact]
Expand Down
4 changes: 2 additions & 2 deletions Test/Attestation/Packed.cs
Expand Up @@ -759,8 +759,8 @@ public void TestFullInvalidAlg()
.Add("sig", signature)
.Add("x5c", X5c));

var ex = Assert.ThrowsAsync<Fido2VerificationException>(() => MakeAttestationResponse());
Assert.Equal("Invalid attestation algorithm", ex.Result.Message);
var ex = Assert.ThrowsAsync<InvalidOperationException>(() => MakeAttestationResponse());
Assert.Equal("Missing or unknown alg 42", ex.Result.Message);
}
}
}
Expand Down

0 comments on commit 7305982

Please sign in to comment.