Skip to content

Commit

Permalink
Use domainstring where neccessary
Browse files Browse the repository at this point in the history
  • Loading branch information
cpiper committed Sep 29, 2017
1 parent 830589f commit 484f653
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 64 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ target/
.settings/
.classpath
.project
src/main/java/META-INF/
79 changes: 32 additions & 47 deletions src/main/java/com/google/webauthn/gaedemo/server/U2fServer.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@
import com.google.webauthn.gaedemo.objects.PublicKeyCredential;
import com.google.webauthn.gaedemo.storage.Credential;


public class U2fServer extends Server {

private static final Logger Log = Logger.getLogger(U2fServer.class.getName());
Expand All @@ -51,24 +50,20 @@ public class U2fServer extends Server {
*/
public static void verifyAssertion(PublicKeyCredential cred, String currentUser, String sessionId,
Credential savedCredential) throws ServletException {
AuthenticatorAssertionResponse assertionResponse =
(AuthenticatorAssertionResponse) cred.getResponse();
AuthenticatorAssertionResponse assertionResponse = (AuthenticatorAssertionResponse) cred.getResponse();

Log.info("-- Verifying signature --");
if (!(savedCredential.getCredential()
.getResponse() instanceof AuthenticatorAttestationResponse)) {
if (!(savedCredential.getCredential().getResponse() instanceof AuthenticatorAttestationResponse)) {
throw new ServletException("Stored attestation missing");
}
AuthenticatorAttestationResponse storedAttData =
(AuthenticatorAttestationResponse) savedCredential.getCredential().getResponse();
AuthenticatorAttestationResponse storedAttData = (AuthenticatorAttestationResponse) savedCredential.getCredential()
.getResponse();

if (!(storedAttData.decodedObject.getAuthenticatorData().getAttData()
.getPublicKey() instanceof EccKey)) {
if (!(storedAttData.decodedObject.getAuthenticatorData().getAttData().getPublicKey() instanceof EccKey)) {
throw new ServletException("U2f-capable key not provided");
}

EccKey publicKey =
(EccKey) storedAttData.decodedObject.getAuthenticatorData().getAttData().getPublicKey();
EccKey publicKey = (EccKey) storedAttData.decodedObject.getAuthenticatorData().getAttData().getPublicKey();
try {
/*
* U2F authentication signatures are signed over the concatenation of
Expand All @@ -84,15 +79,12 @@ public static void verifyAssertion(PublicKeyCredential cred, String currentUser,
String clientDataJson = assertionResponse.getClientDataString();
byte[] clientDataHash = Crypto.sha256Digest(clientDataJson.getBytes());

byte[] signedBytes = Bytes.concat(
storedAttData.getAttestationObject().getAuthenticatorData().getRpIdHash(),
new byte[] {
(assertionResponse.getAuthenticatorData().isUP() == true ? (byte) 1 : (byte) 0)},
ByteBuffer.allocate(4).putInt(assertionResponse.getAuthenticatorData().getSignCount())
.array(),
byte[] signedBytes = Bytes.concat(storedAttData.getAttestationObject().getAuthenticatorData().getRpIdHash(),
new byte[] { (assertionResponse.getAuthenticatorData().isUP() == true ? (byte) 1 : (byte) 0) },
ByteBuffer.allocate(4).putInt(assertionResponse.getAuthenticatorData().getSignCount()).array(),
clientDataHash);
if (!Crypto.verifySignature(Crypto.decodePublicKey(publicKey.getX(), publicKey.getY()),
signedBytes, assertionResponse.getSignature())) {
if (!Crypto.verifySignature(Crypto.decodePublicKey(publicKey.getX(), publicKey.getY()), signedBytes,
assertionResponse.getSignature())) {
throw new ServletException("Signature invalid");
}
} catch (WebAuthnException e) {
Expand All @@ -112,18 +104,17 @@ public static void verifyAssertion(PublicKeyCredential cred, String currentUser,
* @param cred
* @param currentUser
* @param session
* @param origin
* @param originString
* @throws ServletException
*/
public static void registerCredential(PublicKeyCredential cred, String currentUser,
String session, String origin) throws ServletException {
public static void registerCredential(PublicKeyCredential cred, String currentUser, String session,
String originString, String rpId) throws ServletException {

if (!(cred.getResponse() instanceof AuthenticatorAttestationResponse)) {
throw new ServletException("Invalid response structure");
}

AuthenticatorAttestationResponse attResponse =
(AuthenticatorAttestationResponse) cred.getResponse();
AuthenticatorAttestationResponse attResponse = (AuthenticatorAttestationResponse) cred.getResponse();

List<Credential> savedCreds = Credential.load(currentUser);
for (Credential c : savedCreds) {
Expand All @@ -138,31 +129,28 @@ public static void registerCredential(PublicKeyCredential cred, String currentUs
throw new ServletException("Unable to verify session and challenge data", e1);
}

if (!attResponse.getClientData().getOrigin().equals(origin)) {
throw new ServletException("Couldn't verify client data");
if (!attResponse.getClientData().getOrigin().equals(originString)) {
throw new ServletException("Client data origin: " + attResponse.getClientData().getOrigin()
+ " does not match server origin:" + originString);
}

Gson gson = new Gson();
String clientDataJson = attResponse.getClientDataString();
System.out.println(clientDataJson);
byte[] clientDataHash = Crypto.sha256Digest(clientDataJson.getBytes());

byte[] rpIdHash = Crypto.sha256Digest(origin.getBytes());
if (!Arrays.equals(attResponse.getAttestationObject().getAuthenticatorData().getRpIdHash(),
rpIdHash)) {
byte[] rpIdHash = Crypto.sha256Digest(rpId.getBytes());
if (!Arrays.equals(attResponse.getAttestationObject().getAuthenticatorData().getRpIdHash(), rpIdHash)) {
throw new ServletException("RPID hash incorrect");
}

if (!(attResponse.decodedObject.getAuthenticatorData().getAttData()
.getPublicKey() instanceof EccKey)) {
if (!(attResponse.decodedObject.getAuthenticatorData().getAttData().getPublicKey() instanceof EccKey)) {
throw new ServletException("U2f-capable key not provided");
}

FidoU2fAttestationStatement attStmt =
(FidoU2fAttestationStatement) attResponse.decodedObject.getAttestationStatement();
FidoU2fAttestationStatement attStmt = (FidoU2fAttestationStatement) attResponse.decodedObject
.getAttestationStatement();

EccKey publicKey =
(EccKey) attResponse.decodedObject.getAuthenticatorData().getAttData().getPublicKey();
EccKey publicKey = (EccKey) attResponse.decodedObject.getAuthenticatorData().getAttData().getPublicKey();

try {
/*
Expand All @@ -178,22 +166,19 @@ public static void registerCredential(PublicKeyCredential cred, String currentUs
*
* 65 byte user public key represented as {0x4, X, Y}
*/
byte[] signedBytes = Bytes.concat(new byte[] {0}, rpIdHash,
clientDataHash, cred.rawId, new byte[] {0x04},
byte[] signedBytes = Bytes.concat(new byte[] { 0 }, rpIdHash, clientDataHash, cred.rawId, new byte[] { 0x04 },
publicKey.getX(), publicKey.getY());

// TODO Make attStmt.attestnCert an X509Certificate right off the bat.
DataInputStream inputStream = new DataInputStream(
new ByteArrayInputStream(attStmt.attestnCert));
X509Certificate attestationCertificate = (X509Certificate)
CertificateFactory.getInstance("X.509").
generateCertificate(inputStream);
if (!Crypto.verifySignature(attestationCertificate, signedBytes,
attStmt.sig)) {
// TODO Make attStmt.attestnCert an X509Certificate right off the
// bat.
DataInputStream inputStream = new DataInputStream(new ByteArrayInputStream(attStmt.attestnCert));
X509Certificate attestationCertificate = (X509Certificate) CertificateFactory.getInstance("X.509")
.generateCertificate(inputStream);
if (!Crypto.verifySignature(attestationCertificate, signedBytes, attStmt.sig)) {
throw new ServletException("Signature invalid");
}
} catch (CertificateException e) {
throw new ServletException("Error when parsing attestationCertificate");
throw new ServletException("Error when parsing attestationCertificate");
} catch (WebAuthnException e) {
throw new ServletException("Failure while verifying signature", e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,16 @@ public class FinishMakeCredential extends HttpServlet {
private static final long serialVersionUID = 1L;
private final UserService userService = UserServiceFactory.getUserService();

public FinishMakeCredential() {}
public FinishMakeCredential() {
}

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}

@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String currentUser = userService.getCurrentUser().getUserId();
String data = request.getParameter("data");
String session = request.getParameter("session");
Expand Down Expand Up @@ -88,25 +87,24 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response)
PublicKeyCredential cred = new PublicKeyCredential(credentialId, type,
BaseEncoding.base64Url().decode(credentialId), attestation);

//String rpId = (request.isSecure() ? "https://" : "http://") + request.getHeader("Host");
String domain = (request.isSecure() ? "https://" : "http://") + request.getHeader("Host");
String rpId = request.getHeader("Host").split(":")[0];
switch (cred.getAttestationType()) {
case FIDOU2F:
U2fServer.registerCredential(cred, currentUser, session, rpId);
break;
case ANDROIDSAFETYNET:
AndroidSafetyNetServer.registerCredential(cred, currentUser, session, rpId);
break;
case PACKED:
PackedServer.registerCredential(cred, currentUser, session, rpId);
break;
case FIDOU2F:
U2fServer.registerCredential(cred, currentUser, session, domain, rpId);
break;
case ANDROIDSAFETYNET:
AndroidSafetyNetServer.registerCredential(cred, currentUser, session, rpId);
break;
case PACKED:
PackedServer.registerCredential(cred, currentUser, session, rpId);
break;
}

Credential credential = new Credential(cred);
credential.save(currentUser);

PublicKeyCredentialResponse rsp =
new PublicKeyCredentialResponse(true, "Successfully created credential");
PublicKeyCredentialResponse rsp = new PublicKeyCredentialResponse(true, "Successfully created credential");

response.setContentType("application/json");
response.getWriter().println(rsp.toJson());
Expand Down

0 comments on commit 484f653

Please sign in to comment.