Search in sources :

Example 1 with Transports

use of com.google.u2f.server.data.SecurityKeyData.Transports in project OpenUnison by TremoloSecurity.

the class U2FServerUnison method getSignRequest.

@Override
public U2fSignRequest getSignRequest(String accountName, String appId) throws U2FException {
    if (log.isDebugEnabled()) {
        log.debug(">> getSignRequest " + accountName);
    }
    List<SecurityKeyData> securityKeyDataList = dataStore.getSecurityKeyData(accountName);
    byte[] challenge = challengeGenerator.generateChallenge(accountName);
    String challengeBase64 = Base64.encodeBase64URLSafeString(challenge);
    ImmutableList.Builder<RegisteredKey> registeredKeys = ImmutableList.builder();
    if (log.isDebugEnabled()) {
        log.debug("  challenge: " + Hex.encodeHexString(challenge));
    }
    for (SecurityKeyData securityKeyData : securityKeyDataList) {
        SignSessionData sessionData = new SignSessionData(accountName, appId, challenge, securityKeyData.getPublicKey());
        String sessionId = dataStore.storeSessionData(sessionData);
        byte[] keyHandle = securityKeyData.getKeyHandle();
        List<Transports> transports = securityKeyData.getTransports();
        if (log.isDebugEnabled()) {
            log.debug("-- Output --");
            log.debug("  sessionId: " + sessionId);
            log.debug("  keyHandle: " + Hex.encodeHexString(keyHandle));
        }
        String keyHandleBase64 = Base64.encodeBase64URLSafeString(keyHandle);
        if (log.isDebugEnabled()) {
            log.debug("<< getRegisteredKey " + accountName);
        }
        registeredKeys.add(new RegisteredKey(U2FConsts.U2F_V2, keyHandleBase64, transports, appId, sessionId));
    }
    return new U2fSignRequest(challengeBase64, registeredKeys.build());
}
Also used : SignSessionData(com.google.u2f.server.data.SignSessionData) U2fSignRequest(com.google.u2f.server.messages.U2fSignRequest) SecurityKeyData(com.google.u2f.server.data.SecurityKeyData) ImmutableList(com.google.common.collect.ImmutableList) Transports(com.google.u2f.server.data.SecurityKeyData.Transports) RegisteredKey(com.google.u2f.server.messages.RegisteredKey)

Example 2 with Transports

use of com.google.u2f.server.data.SecurityKeyData.Transports in project OpenUnison by TremoloSecurity.

the class U2FServerUnison method processRegistrationResponse.

@Override
public SecurityKeyData processRegistrationResponse(RegistrationResponse registrationResponse, long currentTimeInMillis) throws U2FException {
    log.debug(">> processRegistrationResponse");
    String sessionId = registrationResponse.getSessionId();
    String clientDataBase64 = registrationResponse.getClientData();
    String rawRegistrationDataBase64 = registrationResponse.getRegistrationData();
    log.debug(">> rawRegistrationDataBase64: " + rawRegistrationDataBase64);
    EnrollSessionData sessionData = dataStore.getEnrollSessionData(sessionId);
    if (sessionData == null) {
        throw new U2FException("Unknown session_id");
    }
    String appId = sessionData.getAppId();
    String clientData = new String(Base64.decodeBase64(clientDataBase64));
    byte[] rawRegistrationData = Base64.decodeBase64(rawRegistrationDataBase64);
    if (log.isDebugEnabled()) {
        log.debug("-- Input --");
        log.debug("  sessionId: " + sessionId);
        log.debug("  challenge: " + Hex.encodeHexString(sessionData.getChallenge()));
        log.debug("  accountName: " + sessionData.getAccountName());
        log.debug("  clientData: " + clientData);
        log.debug("  rawRegistrationData: " + Hex.encodeHexString(rawRegistrationData));
    }
    RegisterResponse registerResponse = RawMessageCodec.decodeRegisterResponse(rawRegistrationData);
    byte[] userPublicKey = registerResponse.getUserPublicKey();
    byte[] keyHandle = registerResponse.getKeyHandle();
    X509Certificate attestationCertificate = registerResponse.getAttestationCertificate();
    byte[] signature = registerResponse.getSignature();
    List<Transports> transports = null;
    try {
        transports = U2fAttestation.Parse(attestationCertificate).getTransports();
    } catch (CertificateParsingException e) {
        log.warn("Could not parse transports extension " + e.getMessage());
    }
    if (log.isDebugEnabled()) {
        log.debug("-- Parsed rawRegistrationResponse --");
        log.debug("  userPublicKey: " + Hex.encodeHexString(userPublicKey));
        log.debug("  keyHandle: " + Hex.encodeHexString(keyHandle));
        log.debug("  attestationCertificate: " + attestationCertificate.toString());
        log.debug("  transports: " + transports);
        try {
            log.debug("  attestationCertificate bytes: " + Hex.encodeHexString(attestationCertificate.getEncoded()));
        } catch (CertificateEncodingException e) {
            throw new U2FException("Cannot encode certificate", e);
        }
        log.debug("  signature: " + Hex.encodeHexString(signature));
    }
    byte[] appIdSha256 = crypto.computeSha256(appId.getBytes());
    byte[] clientDataSha256 = crypto.computeSha256(clientData.getBytes());
    byte[] signedBytes = RawMessageCodec.encodeRegistrationSignedBytes(appIdSha256, clientDataSha256, keyHandle, userPublicKey);
    Set<X509Certificate> trustedCertificates = dataStore.getTrustedCertificates();
    boolean found = false;
    for (X509Certificate trusted : trustedCertificates) {
        try {
            attestationCertificate.verify(trusted.getPublicKey());
            found = true;
        } catch (InvalidKeyException | CertificateException | NoSuchAlgorithmException | NoSuchProviderException | SignatureException e) {
        }
    }
    if (!found) {
        if (!this.requireAttestation) {
            log.warn("attestion cert is not trusted");
        } else {
            throw new U2FException("Attestation certificate is not trusted");
        }
    }
    verifyBrowserData(new JsonParser().parse(clientData), "navigator.id.finishEnrollment", sessionData);
    if (log.isDebugEnabled()) {
        log.debug("Verifying signature of bytes " + Hex.encodeHexString(signedBytes));
    }
    if (!crypto.verifySignature(attestationCertificate, signedBytes, signature)) {
        throw new U2FException("Signature is invalid");
    }
    // The first time we create the SecurityKeyData, we set the counter value to 0.
    // We don't actually know what the counter value of the real device is - but it will
    // be something bigger (or equal) to 0, so subsequent signatures will check out ok.
    SecurityKeyData securityKeyData = new SecurityKeyData(currentTimeInMillis, transports, keyHandle, userPublicKey, attestationCertificate, /* initial counter value */
    0);
    dataStore.addSecurityKeyData(sessionData.getAccountName(), securityKeyData);
    if (log.isDebugEnabled()) {
        log.debug("<< processRegistrationResponse");
    }
    return securityKeyData;
}
Also used : EnrollSessionData(com.google.u2f.server.data.EnrollSessionData) CertificateParsingException(java.security.cert.CertificateParsingException) Transports(com.google.u2f.server.data.SecurityKeyData.Transports) CertificateEncodingException(java.security.cert.CertificateEncodingException) CertificateException(java.security.cert.CertificateException) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) SignatureException(java.security.SignatureException) InvalidKeyException(java.security.InvalidKeyException) X509Certificate(java.security.cert.X509Certificate) RegisterResponse(com.google.u2f.key.messages.RegisterResponse) SecurityKeyData(com.google.u2f.server.data.SecurityKeyData) U2FException(com.google.u2f.U2FException) NoSuchProviderException(java.security.NoSuchProviderException) JsonParser(com.google.gson.JsonParser)

Example 3 with Transports

use of com.google.u2f.server.data.SecurityKeyData.Transports in project OpenUnison by TremoloSecurity.

the class U2FServerReferenceImpl method getSignRequest.

@Override
public U2fSignRequest getSignRequest(String accountName, String appId) throws U2FException {
    Log.info(">> getSignRequest " + accountName);
    List<SecurityKeyData> securityKeyDataList = dataStore.getSecurityKeyData(accountName);
    byte[] challenge = challengeGenerator.generateChallenge(accountName);
    String challengeBase64 = Base64.encodeBase64URLSafeString(challenge);
    ImmutableList.Builder<RegisteredKey> registeredKeys = ImmutableList.builder();
    Log.info("  challenge: " + Hex.encodeHexString(challenge));
    for (SecurityKeyData securityKeyData : securityKeyDataList) {
        SignSessionData sessionData = new SignSessionData(accountName, appId, challenge, securityKeyData.getPublicKey());
        String sessionId = dataStore.storeSessionData(sessionData);
        byte[] keyHandle = securityKeyData.getKeyHandle();
        List<Transports> transports = securityKeyData.getTransports();
        Log.info("-- Output --");
        Log.info("  sessionId: " + sessionId);
        Log.info("  keyHandle: " + Hex.encodeHexString(keyHandle));
        String keyHandleBase64 = Base64.encodeBase64URLSafeString(keyHandle);
        Log.info("<< getRegisteredKey " + accountName);
        registeredKeys.add(new RegisteredKey(U2FConsts.U2F_V2, keyHandleBase64, transports, appId, sessionId));
    }
    return new U2fSignRequest(challengeBase64, registeredKeys.build());
}
Also used : SignSessionData(com.google.u2f.server.data.SignSessionData) U2fSignRequest(com.google.u2f.server.messages.U2fSignRequest) SecurityKeyData(com.google.u2f.server.data.SecurityKeyData) ImmutableList(com.google.common.collect.ImmutableList) Transports(com.google.u2f.server.data.SecurityKeyData.Transports) RegisteredKey(com.google.u2f.server.messages.RegisteredKey)

Example 4 with Transports

use of com.google.u2f.server.data.SecurityKeyData.Transports in project OpenUnison by TremoloSecurity.

the class U2fAttestation method Parse.

/**
 * Parses a transport extension from an attestation certificate and returns
 * a List of HardwareFeatures supported by the security key. The specification of
 * the HardwareFeatures in the certificate should match their internal definition in
 * device_auth.proto
 *
 * <p>The expected transport extension value is a BIT STRING containing the enabled
 * transports:
 *
 *  <p>FIDOU2FTransports ::= BIT STRING {
 *       bluetoothRadio(0), -- Bluetooth Classic
 *       bluetoothLowEnergyRadio(1),
 *       uSB(2),
 *       nFC(3)
 *     }
 *
 *   <p>Note that the BIT STRING must be wrapped in an OCTET STRING.
 *   An extension that encodes BT, BLE, and NFC then looks as follows:
 *
 *   <p>SEQUENCE (2 elem)
 *      OBJECT IDENTIFIER 1.3.6.1.4.1.45724.2.1.1
 *      OCTET STRING (1 elem)
 *        BIT STRING (4 bits) 1101
 *
 * @param cert the certificate to parse for extension
 * @return the supported transports as a List of HardwareFeatures or null if no extension
 * was found
 * @throws CertificateParsingException
 */
public static U2fAttestation Parse(X509Certificate cert) throws CertificateParsingException {
    ASN1OctetString extValue = X509ExtensionParsingUtil.extractExtensionValue(cert, TRANSPORT_EXTENSION_OID);
    if (extValue == null) {
        // No Transport extension was found
        return new U2fAttestation(null);
    }
    // Read out the BitString
    ASN1Object asn1Object = X509ExtensionParsingUtil.getAsn1Object(extValue.getOctets());
    if (asn1Object == null || !(asn1Object instanceof DERBitString)) {
        throw new CertificateParsingException("No BitString found in transports extension");
    }
    DERBitString bitString = (DERBitString) asn1Object;
    byte[] values = bitString.getBytes();
    BitSet bitSet = BitSet.valueOf(values);
    // We might have more defined transports than used by the extension
    List<Transports> transports = new ArrayList<Transports>();
    for (int i = 0; i < BITS_IN_A_BYTE; i++) {
        if (bitSet.get(BITS_IN_A_BYTE - i - 1)) {
            transports.add(Transports.values()[i]);
        }
    }
    return new U2fAttestation(transports);
}
Also used : ASN1OctetString(org.bouncycastle.asn1.ASN1OctetString) CertificateParsingException(java.security.cert.CertificateParsingException) Transports(com.google.u2f.server.data.SecurityKeyData.Transports) BitSet(java.util.BitSet) ArrayList(java.util.ArrayList) DERBitString(org.bouncycastle.asn1.DERBitString) ASN1Object(org.bouncycastle.asn1.ASN1Object)

Example 5 with Transports

use of com.google.u2f.server.data.SecurityKeyData.Transports in project OpenUnison by TremoloSecurity.

the class U2FServerReferenceImpl method processRegistrationResponse.

@Override
public SecurityKeyData processRegistrationResponse(RegistrationResponse registrationResponse, long currentTimeInMillis) throws U2FException {
    Log.info(">> processRegistrationResponse");
    String sessionId = registrationResponse.getSessionId();
    String clientDataBase64 = registrationResponse.getClientData();
    String rawRegistrationDataBase64 = registrationResponse.getRegistrationData();
    Log.info(">> rawRegistrationDataBase64: " + rawRegistrationDataBase64);
    EnrollSessionData sessionData = dataStore.getEnrollSessionData(sessionId);
    if (sessionData == null) {
        throw new U2FException("Unknown session_id");
    }
    String appId = sessionData.getAppId();
    String clientData = new String(Base64.decodeBase64(clientDataBase64));
    byte[] rawRegistrationData = Base64.decodeBase64(rawRegistrationDataBase64);
    Log.info("-- Input --");
    Log.info("  sessionId: " + sessionId);
    Log.info("  challenge: " + Hex.encodeHexString(sessionData.getChallenge()));
    Log.info("  accountName: " + sessionData.getAccountName());
    Log.info("  clientData: " + clientData);
    Log.info("  rawRegistrationData: " + Hex.encodeHexString(rawRegistrationData));
    RegisterResponse registerResponse = RawMessageCodec.decodeRegisterResponse(rawRegistrationData);
    byte[] userPublicKey = registerResponse.getUserPublicKey();
    byte[] keyHandle = registerResponse.getKeyHandle();
    X509Certificate attestationCertificate = registerResponse.getAttestationCertificate();
    byte[] signature = registerResponse.getSignature();
    List<Transports> transports = null;
    try {
        transports = U2fAttestation.Parse(attestationCertificate).getTransports();
    } catch (CertificateParsingException e) {
        Log.warning("Could not parse transports extension " + e.getMessage());
    }
    Log.info("-- Parsed rawRegistrationResponse --");
    Log.info("  userPublicKey: " + Hex.encodeHexString(userPublicKey));
    Log.info("  keyHandle: " + Hex.encodeHexString(keyHandle));
    Log.info("  attestationCertificate: " + attestationCertificate.toString());
    Log.info("  transports: " + transports);
    try {
        Log.info("  attestationCertificate bytes: " + Hex.encodeHexString(attestationCertificate.getEncoded()));
    } catch (CertificateEncodingException e) {
        throw new U2FException("Cannot encode certificate", e);
    }
    Log.info("  signature: " + Hex.encodeHexString(signature));
    byte[] appIdSha256 = crypto.computeSha256(appId.getBytes());
    byte[] clientDataSha256 = crypto.computeSha256(clientData.getBytes());
    byte[] signedBytes = RawMessageCodec.encodeRegistrationSignedBytes(appIdSha256, clientDataSha256, keyHandle, userPublicKey);
    Set<X509Certificate> trustedCertificates = dataStore.getTrustedCertificates();
    if (!trustedCertificates.contains(attestationCertificate)) {
        Log.warning("attestion cert is not trusted");
    }
    verifyBrowserData(new JsonParser().parse(clientData), "navigator.id.finishEnrollment", sessionData);
    Log.info("Verifying signature of bytes " + Hex.encodeHexString(signedBytes));
    if (!crypto.verifySignature(attestationCertificate, signedBytes, signature)) {
        throw new U2FException("Signature is invalid");
    }
    // The first time we create the SecurityKeyData, we set the counter value to 0.
    // We don't actually know what the counter value of the real device is - but it will
    // be something bigger (or equal) to 0, so subsequent signatures will check out ok.
    SecurityKeyData securityKeyData = new SecurityKeyData(currentTimeInMillis, transports, keyHandle, userPublicKey, attestationCertificate, /* initial counter value */
    0);
    dataStore.addSecurityKeyData(sessionData.getAccountName(), securityKeyData);
    Log.info("<< processRegistrationResponse");
    return securityKeyData;
}
Also used : EnrollSessionData(com.google.u2f.server.data.EnrollSessionData) CertificateParsingException(java.security.cert.CertificateParsingException) Transports(com.google.u2f.server.data.SecurityKeyData.Transports) CertificateEncodingException(java.security.cert.CertificateEncodingException) X509Certificate(java.security.cert.X509Certificate) RegisterResponse(com.google.u2f.key.messages.RegisterResponse) SecurityKeyData(com.google.u2f.server.data.SecurityKeyData) U2FException(com.google.u2f.U2FException) JsonParser(com.google.gson.JsonParser)

Aggregations

Transports (com.google.u2f.server.data.SecurityKeyData.Transports)5 SecurityKeyData (com.google.u2f.server.data.SecurityKeyData)4 CertificateParsingException (java.security.cert.CertificateParsingException)3 ImmutableList (com.google.common.collect.ImmutableList)2 JsonParser (com.google.gson.JsonParser)2 U2FException (com.google.u2f.U2FException)2 RegisterResponse (com.google.u2f.key.messages.RegisterResponse)2 EnrollSessionData (com.google.u2f.server.data.EnrollSessionData)2 SignSessionData (com.google.u2f.server.data.SignSessionData)2 RegisteredKey (com.google.u2f.server.messages.RegisteredKey)2 U2fSignRequest (com.google.u2f.server.messages.U2fSignRequest)2 CertificateEncodingException (java.security.cert.CertificateEncodingException)2 X509Certificate (java.security.cert.X509Certificate)2 InvalidKeyException (java.security.InvalidKeyException)1 NoSuchAlgorithmException (java.security.NoSuchAlgorithmException)1 NoSuchProviderException (java.security.NoSuchProviderException)1 SignatureException (java.security.SignatureException)1 CertificateException (java.security.cert.CertificateException)1 ArrayList (java.util.ArrayList)1 BitSet (java.util.BitSet)1