Example #1
0
        public virtual void TestDecodeAuthenticateResponse()
        {
            KeySignResponse keySignResponse = RawMessageCodec
                                              .DecodeKeySignResponse(SIGN_RESPONSE_DATA.Segment());

            Assert.AreEqual(new KeySignResponse(UserPresenceVerifierConstants.UserPresentFlag, COUNTER_VALUE, SIGNATURE_AUTHENTICATE), keySignResponse);
        }
Example #2
0
        public virtual void TestEncodeRegisterRequest()
        {
            var registerRequest = new KeyRegisterRequest(APP_ID_ENROLL_SHA256, BROWSER_DATA_ENROLL_SHA256);
            var encodedBytes    = RawMessageCodec.EncodeKeyRegisterRequest(registerRequest);

            CollectionAssert.AreEqual(REGISTRATION_REQUEST_DATA, encodedBytes);
        }
Example #3
0
        public virtual void TestEncodeRegisterSignedBytes()
        {
            var encodedBytes = RawMessageCodec.EncodeKeyRegisterSignedBytes(APP_ID_ENROLL_SHA256,
                                                                            BROWSER_DATA_ENROLL_SHA256, KEY_HANDLE, USER_PUBLIC_KEY_ENROLL_HEX);

            CollectionAssert.AreEqual(EXPECTED_REGISTER_SIGNED_BYTES, encodedBytes);
        }
Example #4
0
        public async Task <RegisterResponse> Register(ICollection <RegisterRequest> registrationRequests,
                                                      ICollection <SignRequest> signRequests, CancellationToken cancellationToken = default(CancellationToken))
        {
            var appIds = registrationRequests
                         .Select(r => r.AppId)
                         .Concat(signRequests.Select(r => r.AppId))
                         .Distinct()
                         .ToList();

            await CheckOriginAndAppIdsAsync(appIds, cancellationToken);

            var signInfos       = signRequests.Select(GenerateSignInfo).ToDictionary(s => s.KeySignRequest);
            var keySignRequests = signInfos.Keys.ToList();

            var registerInfos       = registrationRequests.Select(GenerateRegisterInfo).ToDictionary(s => s.KeyRegisterRequest);
            var keyRegisterRequests = registerInfos.Keys.ToList();
            var result = await keyOperations.Register(keyRegisterRequests, keySignRequests,
                                                      cancellationToken);

            if (!result.IsSuccess)
            {
                return(null);
            }

            var registerInfo = registerInfos[result.Request];

            return(new RegisterResponse(
                       WebSafeBase64Converter.ToBase64String(RawMessageCodec.EncodeKeyRegisterResponse(result.Response)),
                       WebSafeBase64Converter.ToBase64String(registerInfo.ClientDataBase64),
                       registerInfo.RegisterRequest.SessionId));
        }
Example #5
0
        public virtual void TestEncodeAuthenticateSignedBytes()
        {
            var encodedBytes = RawMessageCodec.EncodeKeySignSignedBytes(APP_ID_SIGN_SHA256,
                                                                        UserPresenceVerifierConstants.UserPresentFlag, COUNTER_VALUE, BROWSER_DATA_SIGN_SHA256);

            CollectionAssert.AreEqual(EXPECTED_AUTHENTICATE_SIGNED_BYTES, encodedBytes);
        }
Example #6
0
        /// <exception cref="U2FException" />
        public KeySignResponse Authenticate(KeySignRequest keySignRequest)
        {
            if (keySignRequest == null)
            {
                throw new ArgumentNullException(nameof(keySignRequest));
            }

            log.Info(">> authenticate");

            var applicationSha256 = keySignRequest.ApplicationSha256;
            var challengeSha256   = keySignRequest.ChallengeSha256;
            var keyHandle         = keySignRequest.KeyHandle;

            log.Info(" -- Inputs --");
            log.Info("  applicationSha256: " + applicationSha256.ToHexString());
            log.Info("  challengeSha256: " + challengeSha256.ToHexString());
            log.Info("  keyHandle: " + keyHandle.ToHexString());

            var keyPair      = dataStore.GetKeyPair(keyHandle);
            var counter      = dataStore.IncrementCounter();
            var userPresence = userPresenceVerifier.VerifyUserPresence();
            var signedData   = RawMessageCodec.EncodeKeySignSignedBytes(applicationSha256, userPresence, counter,
                                                                        challengeSha256);

            log.Info("Signing bytes " + signedData.ToHexString());
            var signature = crypto.Sign(signedData, keyPair.PrivateKey);

            log.Info(" -- Outputs --");
            log.Info("  userPresence: " + userPresence);
            log.Info("  counter: " + counter);
            log.Info("  signature: " + signature.ToHexString());
            log.Info("<< authenticate");

            return(new KeySignResponse(userPresence, counter, signature));
        }
Example #7
0
        public virtual void TestDecodeRegisterRequest()
        {
            KeyRegisterRequest keyRegisterRequest = RawMessageCodec
                                                    .DecodeKeyRegisterRequest(REGISTRATION_REQUEST_DATA);

            Assert.AreEqual(new KeyRegisterRequest(APP_ID_ENROLL_SHA256
                                                   , BROWSER_DATA_ENROLL_SHA256), keyRegisterRequest);
        }
Example #8
0
        public virtual void TestEncodeAuthenticateResponse()
        {
            var authenticateResponse = new KeySignResponse(UserPresenceVerifierConstants.UserPresentFlag,
                                                           COUNTER_VALUE, SIGNATURE_AUTHENTICATE);
            var encodedBytes = RawMessageCodec.EncodeKeySignResponse(authenticateResponse);

            CollectionAssert.AreEqual(SIGN_RESPONSE_DATA, encodedBytes);
        }
Example #9
0
        public virtual void TestDecodeAuthenticateRequest()
        {
            var authenticateRequest = RawMessageCodec.DecodeKeySignRequest(SIGN_REQUEST_DATA);

            Assert.AreEqual(
                new KeySignRequest(U2FVersion.V2, BROWSER_DATA_SIGN_SHA256,
                                   APP_ID_SIGN_SHA256, KEY_HANDLE), authenticateRequest);
        }
Example #10
0
        public virtual void TestDecodeRegisterResponse()
        {
            var registerResponse = RawMessageCodec.DecodeKeyRegisterResponse(REGISTRATION_RESPONSE_DATA.Segment());

            Assert.AreEqual(
                new KeyRegisterResponse(USER_PUBLIC_KEY_ENROLL_HEX, KEY_HANDLE, VENDOR_CERTIFICATE, SIGNATURE_ENROLL),
                registerResponse);
        }
Example #11
0
        public virtual void TestEncodeAuthenticateRequest()
        {
            var authenticateRequest = new KeySignRequest(U2FVersion.V2,
                                                         BROWSER_DATA_SIGN_SHA256, APP_ID_SIGN_SHA256, KEY_HANDLE);
            var encodedBytes = RawMessageCodec.EncodeKeySignRequest(authenticateRequest);

            CollectionAssert.AreEqual(SIGN_REQUEST_DATA, encodedBytes);
        }
Example #12
0
        public virtual void TestEncodeRegisterResponse()
        {
            var registerResponse = new KeyRegisterResponse(USER_PUBLIC_KEY_ENROLL_HEX, KEY_HANDLE, VENDOR_CERTIFICATE,
                                                           SIGNATURE_ENROLL);
            var encodedBytes = RawMessageCodec.EncodeKeyRegisterResponse(registerResponse);

            CollectionAssert.AreEqual(REGISTRATION_RESPONSE_DATA, encodedBytes);
        }
Example #13
0
        public Task <KeyResponse <KeyRegisterResponse> > RegisterAsync(KeyRegisterRequest request, CancellationToken cancellationToken = new CancellationToken(),
                                                                       bool invididualAttestation = false)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            log.Info(">> register");

            var applicationSha256 = request.ApplicationSha256;
            var challengeSha256   = request.ChallengeSha256;

            log.Info(" -- Inputs --");
            log.Info("  applicationSha256: " + applicationSha256.ToHexString());
            log.Info("  challengeSha256: " + challengeSha256.ToHexString());

            var userPresent = userPresenceVerifier.VerifyUserPresence();

            if ((userPresent & UserPresenceVerifierConstants.UserPresentFlag) == 0)
            {
                return(TestOfUserPresenceRequired <KeyRegisterResponse>());
            }

            var keyPair   = keyPairGenerator.GenerateKeyPair(applicationSha256, challengeSha256);
            var keyHandle = keyHandleGenerator.GenerateKeyHandle(applicationSha256, keyPair);

            dataStore.StoreKeyPair(keyHandle, keyPair);

            var userPublicKey = keyPairGenerator.EncodePublicKey(keyPair.PublicKey);
            var signedData    = RawMessageCodec.EncodeKeyRegisterSignedBytes(applicationSha256, challengeSha256, keyHandle,
                                                                             userPublicKey);

            log.Info("Signing bytes " + signedData.ToHexString());
            var signature = crypto.Sign(signedData, certificatePrivateKey);

            log.Info(" -- Outputs --");
            log.Info("  userPublicKey: " + userPublicKey.ToHexString());
            log.Info("  keyHandle: " + keyHandle.ToHexString());
            log.Info("  vendorCertificate: " + vendorCertificate);
            log.Info("  signature: " + signature.ToHexString());
            log.Info("<< register");

            var response     = new KeyRegisterResponse(userPublicKey, keyHandle, vendorCertificate, signature);
            var responseData = RawMessageCodec.EncodeKeyRegisterResponse(response).Segment();
            var apdu         = new ApduResponse(ApduResponseStatus.NoError, responseData);
            var keyResponse  = new KeyResponse <KeyRegisterResponse>(apdu, response, KeyResponseStatus.Success);

            return(TaskEx.FromResult(keyResponse));
        }
Example #14
0
        public Task <KeyResponse <KeySignResponse> > SignAsync(KeySignRequest request, CancellationToken cancellationToken = new CancellationToken(),
                                                               bool noWink = false)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            log.Info(">> authenticate");

            var applicationSha256 = request.ApplicationSha256;
            var challengeSha256   = request.ChallengeSha256;
            var keyHandle         = request.KeyHandle;

            log.Info(" -- Inputs --");
            log.Info("  applicationSha256: " + applicationSha256.ToHexString());
            log.Info("  challengeSha256: " + challengeSha256.ToHexString());
            log.Info("  keyHandle: " + keyHandle.ToHexString());

            var keyPair     = dataStore.GetKeyPair(keyHandle);
            var counter     = dataStore.IncrementCounter();
            var userPresent = userPresenceVerifier.VerifyUserPresence();

            if ((userPresent & UserPresenceVerifierConstants.UserPresentFlag) == 0)
            {
                return(TestOfUserPresenceRequired <KeySignResponse>());
            }

            var signedData = RawMessageCodec.EncodeKeySignSignedBytes(applicationSha256, userPresent, counter,
                                                                      challengeSha256);

            log.Info("Signing bytes " + signedData.ToHexString());
            var signature = crypto.Sign(signedData, keyPair.PrivateKey);

            log.Info(" -- Outputs --");
            log.Info("  userPresence: " + userPresent);
            log.Info("  counter: " + counter);
            log.Info("  signature: " + signature.ToHexString());
            log.Info("<< authenticate");

            var response     = new KeySignResponse(userPresent, counter, signature);
            var responseData = RawMessageCodec.EncodeKeySignResponse(response).Segment();
            var apdu         = new ApduResponse(ApduResponseStatus.NoError, responseData);
            var keyResponse  = new KeyResponse <KeySignResponse>(apdu, response, KeyResponseStatus.Success);

            return(TaskEx.FromResult(keyResponse));
        }
Example #15
0
        /// <exception cref="U2FException" />
        public KeyRegisterResponse Register(KeyRegisterRequest keyRegisterRequest)
        {
            if (keyRegisterRequest == null)
            {
                throw new ArgumentNullException(nameof(keyRegisterRequest));
            }

            log.Info(">> register");

            var applicationSha256 = keyRegisterRequest.ApplicationSha256;
            var challengeSha256   = keyRegisterRequest.ChallengeSha256;

            log.Info(" -- Inputs --");
            log.Info("  applicationSha256: " + applicationSha256.ToHexString());
            log.Info("  challengeSha256: " + challengeSha256.ToHexString());

            var userPresent = userPresenceVerifier.VerifyUserPresence();

            if ((userPresent & UserPresenceVerifierConstants.UserPresentFlag) == 0)
            {
                throw new U2FException("Cannot verify user presence");
            }

            var keyPair   = keyPairGenerator.GenerateKeyPair(applicationSha256, challengeSha256);
            var keyHandle = keyHandleGenerator.GenerateKeyHandle(applicationSha256, keyPair);

            dataStore.StoreKeyPair(keyHandle, keyPair);

            var userPublicKey = keyPairGenerator.EncodePublicKey(keyPair.PublicKey);
            var signedData    = RawMessageCodec.EncodeKeyRegisterSignedBytes(applicationSha256, challengeSha256, keyHandle,
                                                                             userPublicKey);

            log.Info("Signing bytes " + signedData.ToHexString());
            var signature = crypto.Sign(signedData, certificatePrivateKey);

            log.Info(" -- Outputs --");
            log.Info("  userPublicKey: " + userPublicKey.ToHexString());
            log.Info("  keyHandle: " + keyHandle.ToHexString());
            log.Info("  vendorCertificate: " + vendorCertificate);
            log.Info("  signature: " + signature.ToHexString());
            log.Info("<< register");

            return(new KeyRegisterResponse(userPublicKey, keyHandle, vendorCertificate, signature));
        }
        public void Register(string origin, string accountName)
        {
            var registrationRequest = server.GetRegistrationRequest(accountName, origin);

            if (!registrationRequest.Version.Equals(U2FConsts.U2Fv2))
            {
                throw new U2FException($"Unsupported protocol version: {registrationRequest.Version}");
            }
            appIdVerifier.ValidateOrigin(registrationRequest.AppId, origin);
            var    channelIdJson = channelIdProvider.GetJsonChannelId();
            string clientData;
            var    registerRequest           = RegistrationRequestToRegisterRequest(origin, registrationRequest, channelIdJson, out clientData, crypto);
            var    registerResponse          = key.Register(registerRequest);
            var    rawRegisterResponse       = RawMessageCodec.EncodeKeyRegisterResponse(registerResponse);
            var    rawRegisterResponseBase64 = WebSafeBase64Converter.ToBase64String(rawRegisterResponse);
            var    clientDataBase64          = WebSafeBase64Converter.ToBase64String(Encoding.UTF8.GetBytes(clientData));

            server.ProcessRegistrationResponse(
                new RegisterResponse(rawRegisterResponseBase64, clientDataBase64, registrationRequest.SessionId),
                clock.Now.ToUnixTimeMilliseconds());
        }
        public void Authenticate(string origin, string accountName)
        {
            // the key can be used to sign any of the requests - we're gonna sign the first one.
            var signRequest = server.GetSignRequests(accountName, origin)[0];

            if (!signRequest.Version.Equals(U2FConsts.U2Fv2))
            {
                throw new U2FException($"Unsupported protocol version: {signRequest.Version}");
            }
            appIdVerifier.ValidateOrigin(signRequest.AppId, origin);
            var    channelIdJson = channelIdProvider.GetJsonChannelId();
            string clientData;
            var    authenticateRequest = SignRequestToAuthenticateRequest(origin, signRequest, channelIdJson, out clientData, crypto);

            var authenticateResponse      = key.Authenticate(authenticateRequest);
            var rawAuthenticateResponse   = RawMessageCodec.EncodeKeySignResponse(authenticateResponse);
            var rawAuthenticateResponse64 = WebSafeBase64Converter.ToBase64String(rawAuthenticateResponse);
            var clientDataBase64          = WebSafeBase64Converter.ToBase64String(Encoding.UTF8.GetBytes(clientData));

            server.ProcessSignResponse(new SignResponse(clientDataBase64, rawAuthenticateResponse64,
                                                        signRequest.Challenge, signRequest.SessionId, signRequest.AppId));
        }
Example #18
0
        public SecurityKeyData ProcessSignResponse(SignResponse signResponse)
        {
            log.Info(">> processSignResponse");
            var sessionId         = signResponse.SessionId;
            var browserDataBase64 = signResponse.Bd;
            var rawSignDataBase64 = signResponse.Sign;
            var sessionData       = dataStore.GetSignSessionData(sessionId);

            if (sessionData == null)
            {
                throw new U2FException("Unknown session_id");
            }

            var appId           = sessionData.AppId;
            var securityKeyData = dataStore
                                  .GetSecurityKeyData(sessionData.AccountName)
                                  .FirstOrDefault(k => sessionData.GetPublicKey().SequenceEqual(k.PublicKey));

            if (securityKeyData == null)
            {
                throw new U2FException("No security keys registered for this user");
            }

            var browserDataBytes = WebSafeBase64Converter.FromBase64String(browserDataBase64);
            var browserData      = Encoding.UTF8.GetString(browserDataBytes, 0, browserDataBytes.Length);
            var rawSignData      = WebSafeBase64Converter.FromBase64String(rawSignDataBase64);

            log.Info("-- Input --");
            log.Info("  sessionId: " + sessionId);
            log.Info("  publicKey: " + securityKeyData.PublicKey.ToHexString());
            log.Info("  challenge: " + sessionData.Challenge.ToHexString());
            log.Info("  accountName: " + sessionData.AccountName);
            log.Info("  browserData: " + browserData);
            log.Info("  rawSignData: " + rawSignData.ToHexString());

            VerifyBrowserData(browserData, "navigator.id.getAssertion", sessionData);
            var authenticateResponse = RawMessageCodec.DecodeKeySignResponse(rawSignData.Segment());
            var userPresence         = authenticateResponse.UserPresence;
            var counter   = authenticateResponse.Counter;
            var signature = authenticateResponse.Signature;

            log.Info("-- Parsed rawSignData --");
            log.Info("  userPresence: " + userPresence.ToString("X2"));
            log.Info("  counter: " + counter);
            log.Info("  signature: " + signature.ToHexString());

            if (userPresence != UserPresenceVerifierConstants.UserPresentFlag)
            {
                throw new U2FException("User presence invalid during authentication");
            }
            if (counter <= securityKeyData.Counter)
            {
                throw new U2FException("Counter value smaller than expected!");
            }

            var appIdSha256       = cryto.ComputeSha256(Encoding.UTF8.GetBytes(appId));
            var browserDataSha256 = cryto.ComputeSha256(Encoding.UTF8.GetBytes(browserData));
            var signedBytes       = RawMessageCodec.EncodeKeySignSignedBytes(appIdSha256, userPresence, counter,
                                                                             browserDataSha256);

            log.Info("Verifying signature of bytes " + signedBytes.ToHexString());
            if (!cryto.VerifySignature(cryto.DecodePublicKey(securityKeyData.PublicKey), signedBytes, signature))
            {
                throw new U2FException("Signature is invalid");
            }
            dataStore.UpdateSecurityKeyCounter(sessionData.AccountName, securityKeyData.PublicKey, counter);
            log.Info("<< processSignResponse");
            return(securityKeyData);
        }
Example #19
0
        /// <exception cref="U2FException" />
        public SecurityKeyData ProcessRegistrationResponse(RegisterResponse registrationResponse,
                                                           long currentTimeInMillis)
        {
            log.Info(">> processRegistrationResponse");

            var sessionId                 = registrationResponse.SessionId;
            var browserDataBase64         = registrationResponse.Bd;
            var rawRegistrationDataBase64 = registrationResponse.RegistrationData;
            var sessionData               = dataStore.GetEnrollSessionData(sessionId);

            if (sessionData == null)
            {
                throw new U2FException("Unknown session_id");
            }
            var appId               = sessionData.AppId;
            var rawBrowserData      = WebSafeBase64Converter.FromBase64String(browserDataBase64);
            var browserData         = Encoding.UTF8.GetString(rawBrowserData, 0, rawBrowserData.Length);
            var rawRegistrationData = WebSafeBase64Converter.FromBase64String(rawRegistrationDataBase64);

            log.Info("-- Input --");
            log.Info("  sessionId: " + sessionId);
            log.Info("  challenge: " + sessionData.Challenge.ToHexString());
            log.Info("  accountName: " + sessionData.AccountName);
            log.Info("  browserData: " + browserData);
            log.Info("  rawRegistrationData: " + rawRegistrationData.ToHexString());

            var registerResponse       = RawMessageCodec.DecodeKeyRegisterResponse(rawRegistrationData.Segment());
            var userPublicKey          = registerResponse.UserPublicKey;
            var keyHandle              = registerResponse.KeyHandle;
            var attestationCertificate = registerResponse.AttestationCertificate;
            var signature              = registerResponse.Signature;
            IList <SecurityKeyDataTransports> transports = null;

            try
            {
                transports = ParseTransportsExtension(attestationCertificate);
            }
            catch (CertificateParsingException e1)
            {
                log.Warn("Could not parse transports extension " + e1.Message);
            }
            log.Info("-- Parsed rawRegistrationResponse --");
            log.Info("  userPublicKey: " + userPublicKey.ToHexString
                         ());
            log.Info("  keyHandle: " + keyHandle.ToHexString());
            log.Info("  attestationCertificate: " + SecurityKeyData.SafeCertificateToString(attestationCertificate));
            log.Info("  transports: " + transports);
            log.Info("  attestationCertificate bytes: " + attestationCertificate.GetEncoded().ToHexString());
            log.Info("  signature: " + signature.ToHexString());

            var appIdSha256       = cryto.ComputeSha256(Encoding.UTF8.GetBytes(appId));
            var browserDataSha256 = cryto.ComputeSha256(Encoding.UTF8.GetBytes(browserData));
            var signedBytes       = RawMessageCodec.EncodeKeyRegisterSignedBytes(appIdSha256, browserDataSha256, keyHandle,
                                                                                 userPublicKey);
            var trustedCertificates = dataStore.GetTrustedCertificates();

            if (!trustedCertificates.Contains(attestationCertificate))
            {
                log.Warn("Attestion cert is not trusted");
            }

            VerifyBrowserData(browserData, "navigator.id.finishEnrollment", sessionData);

            log.Info("Verifying signature of bytes " + signedBytes.ToHexString());
            if (!cryto.VerifySignature(attestationCertificate, signedBytes, signature))
            {
                throw new U2FException("Signature is invalid");
            }

            // The first time we create the SecurityKeyData, we set the counter value to -1.
            // We don't actually know what the counter value of the real device is - but it will
            // be something bigger than -1, so subsequent signatures will check out ok.
            var securityKeyData = new SecurityKeyData(currentTimeInMillis, transports, keyHandle, userPublicKey,
                                                      attestationCertificate, -1);

            /* initial counter value */
            dataStore.AddSecurityKeyData(sessionData.AccountName, securityKeyData);
            log.Info("<< processRegistrationResponse");
            return(securityKeyData);
        }