private void VerifyCred(string format, ReadOnlySpan <byte> authData, ReadOnlySpan <byte> x5C, ReadOnlySpan <byte> signature) { var ext = FidoExtensions.None; if (UseHmac) { ext |= FidoExtensions.HmacSecret; } if (BlobKey != null) { ext |= FidoExtensions.LargeBlobKey; } using (var cred = new FidoCredential()) { cred.SetType(FromKeyType(Type)); cred.SetClientData(Cd); cred.Rp = new FidoCredentialRp { Id = "localhost", Name = "sweet home localhost" }; cred.AuthData = authData; cred.SetExtensions(ext); if (ResidentKey) { cred.SetResidentKeyRequired(true); } if (UserVerificationRequired) { cred.SetUserVerificationRequried(true); } cred.SetX509(x5C); cred.Signature = signature; cred.Format = format; cred.Verify(); if (PublicKey != null) { if (Type == KeyType.ECDSA) { WriteEcPublicKey(cred.PublicKey); } else { WriteRsaPublicKey(cred.PublicKey.ToArray()); } } if (CredentialId != null) { File.WriteAllBytes(CredentialId, cred.Id.ToArray()); } } }
//Note: Registering a security key like this would usually happen in the browser via javascript extension //It could be done on behalf of the user via the MMC snapin private static MakeCredentialResult MakeDeviceCredential(string devicePath, bool useHmacExtension, FidoCose algorithmType, List <string> excludedCredentials, string pin, bool requireUv) { //Use these values on the commandline when manually creating a credentail using fido2-token in the Yubico libfido2 toolkit //var base64cdh = Convert.ToBase64String(Cdh); //var base64UserId = Convert.ToBase64String(UserId); var ext = useHmacExtension ? FidoExtensions.HmacSecret : FidoExtensions.None; //Instructs the authenticator to store the key material on the device. Default false in the spec. //var residentKey = false; //Instructs the authenticator to require a gesture that verifies the user to complete the request. //Examples of such gestures are fingerprint scan or a PIN. Default false in the spec. //var userVerificationRequired = false; using (var cred = new FidoCredential()) { using (var dev = new FidoDevice()) { dev.Open(devicePath); //if (excludedCredentials != null) //{ // foreach (var excludedCredential in excludedCredentials) // { // var credId = Convert.FromBase64String(excludedCredential); // cred.Exclude(credId); // } //} cred.SetType(algorithmType); cred.ClientDataHash = Cdh; cred.Rp = new FidoCredentialRp { Id = "relyingparty", //Name = "sweet home localhost" }; cred.SetUser(new FidoCredentialUser { Id = UserId, //DisplayName = "john smith", Name = "johnsmith2" //Icon = "http://secone.io/logo.png" }); cred.SetExtensions(ext); //Only set these options if we have the capability if (requireUv) { cred.SetOptions(false, true); } //Make the credential, including the device pin if required dev.MakeCredential(cred, pin); //Seems like we are forcing a close asap even though we have a using dev.Close(); } //Now verify the credential was created successfully, and write out the public key information and credential id MakeCredentialResult result; using (var verify = new FidoCredential()) { verify.SetType(algorithmType); verify.ClientDataHash = Cdh; verify.Rp = new FidoCredentialRp { Id = "relyingparty", //Name = "sweet home localhost" }; verify.AuthData = cred.AuthData; verify.SetExtensions(ext); if (requireUv) { verify.SetOptions(false, true); } verify.SetX509(cred.X5C); verify.Signature = cred.Signature; verify.Format = cred.Format; //Throws a CtapException if it fails. verify.Verify(); //Now write out the information, because we need the public key created by the device for future assertions result.PublicKey = Convert.ToBase64String(verify.PublicKey.ToArray()); result.CredentialId = Convert.ToBase64String(verify.Id.ToArray()); } //Also bang this out to file for future reference var builder = new StringBuilder(); builder.AppendLine($"CredentialId:{result.CredentialId}"); builder.AppendLine($"PublicKey:{result.PublicKey}"); File.WriteAllText($"Credential.txt", builder.ToString()); return(result); } }