/* * oxAuth is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. * * Copyright (c) 2014, Gluu */ package org.xdi.oxauth.service.fido.u2f; import java.io.IOException; import javax.ejb.Stateless; import javax.inject.Inject; import javax.inject.Named; import org.apache.commons.io.IOUtils; import org.slf4j.Logger; import org.xdi.oxauth.crypto.signature.SHA256withECDSASignatureVerification; import org.xdi.oxauth.model.exception.SignatureException; import org.xdi.oxauth.model.fido.u2f.exception.BadInputException; import org.xdi.oxauth.model.fido.u2f.message.RawAuthenticateResponse; import org.xdi.oxauth.model.fido.u2f.protocol.ClientData; import org.xdi.oxauth.model.util.Base64Util; import org.xdi.util.io.ByteDataInputStream; import com.google.common.io.ByteArrayDataOutput; import com.google.common.io.ByteStreams; /** * Provides operations with U2F RAW authentication response * * @author Yuriy Movchan Date: 05/20/2015 */ @Stateless @Named public class RawAuthenticationService { public static final String AUTHENTICATE_GET_TYPE = "navigator.id.getAssertion"; public static final String AUTHENTICATE_CANCEL_TYPE = "navigator.id.cancelAssertion"; public static final String[] SUPPORTED_AUTHENTICATE_TYPES = new String[] { AUTHENTICATE_GET_TYPE, AUTHENTICATE_CANCEL_TYPE }; @Inject private Logger log; @Inject @Named(value = "sha256withECDSASignatureVerification") private SHA256withECDSASignatureVerification signatureVerification; public RawAuthenticateResponse parseRawAuthenticateResponse(String rawDataBase64) { ByteDataInputStream bis = new ByteDataInputStream(Base64Util.base64urldecode(rawDataBase64)); try { return new RawAuthenticateResponse(bis.readSigned(), bis.readInt(), bis.readAll()); } catch (IOException ex) { throw new BadInputException("Failed to parse RAW authenticate response", ex); } finally { IOUtils.closeQuietly(bis); } } public void checkSignature(String appId, ClientData clientData, RawAuthenticateResponse rawAuthenticateResponse, byte[] publicKey) throws BadInputException { String rawClientData = clientData.getRawClientData(); byte[] signedBytes = packBytesToSign(signatureVerification.hash(appId), rawAuthenticateResponse.getUserPresence(), rawAuthenticateResponse.getCounter(), signatureVerification.hash(rawClientData)); try { signatureVerification.checkSignature(signatureVerification.decodePublicKey(publicKey), signedBytes, rawAuthenticateResponse.getSignature()); } catch (SignatureException ex) { throw new BadInputException("Failed to checkSignature", ex); } } private byte[] packBytesToSign(byte[] appIdHash, byte userPresence, long counter, byte[] challengeHash) { ByteArrayDataOutput encoded = ByteStreams.newDataOutput(); encoded.write(appIdHash); encoded.write(userPresence); encoded.writeInt((int) counter); encoded.write(challengeHash); return encoded.toByteArray(); } }