Java tutorial
/* * Copyright 2014 Yubico. * Copyright 2014 Google Inc. All rights reserved. * * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file or at * https://developers.google.com/open-source/licenses/bsd */ package u2f.data.messages.key; import com.google.common.base.Objects; import com.google.common.io.ByteArrayDataOutput; import com.google.common.io.ByteStreams; import u2f.crypto.BouncyCastleCrypto; import u2f.crypto.Crypto; import u2f.data.DeviceRegistration; import u2f.data.messages.key.util.ByteInputStream; import u2f.data.messages.key.util.CertificateParser; import u2f.data.messages.key.util.U2fB64Encoding; import u2f.exceptions.U2fBadInputException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.Arrays; /** * The register response produced by the token/key, which is transformed by the client into an RegisterResponse * and sent to the server. */ public class RawRegisterResponse { public static final byte REGISTRATION_RESERVED_BYTE_VALUE = (byte) 0x05; public static final byte REGISTRATION_SIGNED_RESERVED_BYTE_VALUE = (byte) 0x00; /** * The (uncompressed) x,y-representation of a curve point on the P-256 * NIST elliptic curve. */ final byte[] userPublicKey; /** * A handle that allows the U2F token to identify the generated key pair. */ final byte[] keyHandle; final X509Certificate attestationCertificate; /** * A ECDSA signature (on P-256) */ final byte[] signature; private final Crypto crypto; public RawRegisterResponse(byte[] userPublicKey, byte[] keyHandle, X509Certificate attestationCertificate, byte[] signature) { this(userPublicKey, keyHandle, attestationCertificate, signature, new BouncyCastleCrypto()); } public RawRegisterResponse(byte[] userPublicKey, byte[] keyHandle, X509Certificate attestationCertificate, byte[] signature, Crypto crypto) { this.userPublicKey = userPublicKey; this.keyHandle = keyHandle; this.attestationCertificate = attestationCertificate; this.signature = signature; this.crypto = crypto; } public static RawRegisterResponse fromBase64(String rawDataBase64, Crypto crypto) throws U2fBadInputException { ByteInputStream bytes = new ByteInputStream(U2fB64Encoding.decode(rawDataBase64)); byte reservedByte = bytes.readSigned(); if (reservedByte != REGISTRATION_RESERVED_BYTE_VALUE) { throw new U2fBadInputException("Incorrect value of reserved byte. Expected: " + REGISTRATION_RESERVED_BYTE_VALUE + ". Was: " + reservedByte); } try { return new RawRegisterResponse(bytes.read(65), bytes.read(bytes.readUnsigned()), CertificateParser.parseDer(bytes), bytes.readAll(), crypto); } catch (CertificateException e) { throw new U2fBadInputException("Malformed attestation certificate", e); } } public static byte[] packBytesToSign(byte[] appIdHash, byte[] clientDataHash, byte[] keyHandle, byte[] userPublicKey) { ByteArrayDataOutput encoded = ByteStreams.newDataOutput(); encoded.write(REGISTRATION_SIGNED_RESERVED_BYTE_VALUE); encoded.write(appIdHash); encoded.write(clientDataHash); encoded.write(keyHandle); encoded.write(userPublicKey); return encoded.toByteArray(); } public void checkSignature(String appId, String clientData) throws U2fBadInputException { byte[] signedBytes = packBytesToSign(crypto.hash(appId), crypto.hash(clientData), keyHandle, userPublicKey); crypto.checkSignature(attestationCertificate, signedBytes, signature); } public DeviceRegistration createDevice() throws U2fBadInputException { return new DeviceRegistration(U2fB64Encoding.encode(keyHandle), U2fB64Encoding.encode(userPublicKey), attestationCertificate, DeviceRegistration.INITIAL_COUNTER_VALUE); } @Override public int hashCode() { return Objects.hashCode(userPublicKey, keyHandle, attestationCertificate, signature); } @Override public boolean equals(Object obj) { if (!(obj instanceof RawRegisterResponse)) return false; RawRegisterResponse other = (RawRegisterResponse) obj; return Objects.equal(attestationCertificate, other.attestationCertificate) && Arrays.equals(keyHandle, other.keyHandle) && Arrays.equals(signature, other.signature) && Arrays.equals(userPublicKey, other.userPublicKey); } }