Skip to content

Commit

Permalink
Merge pull request eBay#9 from eBay/auth_rsa_support
Browse files Browse the repository at this point in the history
Added support for UAF_ALG_SIGN_RSASSA_PSS_SHA256_RAW/DER
  • Loading branch information
npesic committed Feb 17, 2016
2 parents 99341d7 + c220285 commit a3fa311
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 75 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,11 @@
import java.util.logging.Logger;

import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.asn1.pkcs.RSAPublicKey;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.crypto.params.RSAKeyParameters;
import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
import org.bouncycastle.crypto.util.SubjectPublicKeyInfoFactory;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import org.bouncycastle.jce.ECNamedCurveTable;
import org.bouncycastle.jce.ECPointUtil;
Expand All @@ -69,15 +72,15 @@ public static KeyPair getKeyPair()
g.initialize(ecGenSpec, new SecureRandom());
return g.generateKeyPair();
}

public static KeyPair getRSAKeyPair()
throws InvalidAlgorithmParameterException,
NoSuchAlgorithmException, NoSuchProviderException {
KeyPairGenerator g = KeyPairGenerator.getInstance("RSA", "BC");
g.initialize(2048);
return g.generateKeyPair();
}

static public RSAKeyParameters generatePrivateKeyParameter(RSAPrivateKey key) {
if (key instanceof RSAPrivateCrtKey) {
RSAPrivateCrtKey k = (RSAPrivateCrtKey) key;
Expand All @@ -91,7 +94,7 @@ static public RSAKeyParameters generatePrivateKeyParameter(RSAPrivateKey key) {
k.getPrivateExponent());
}
}

public static byte[] getKeyAsRawBytes(String base64EncodedPubKey)
throws InvalidKeySpecException, NoSuchAlgorithmException,
NoSuchProviderException, IOException {
Expand Down Expand Up @@ -209,6 +212,14 @@ public static PublicKey getPubKeyFromCurve(byte[] pubKey, String curveName)
ECPublicKey pk = (ECPublicKey) kf.generatePublic(pubKeySpec);
return pk;
}

public static PublicKey getRSAPublicKey(byte[] encodedPubKey) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
RSAPublicKey pubKey8 = RSAPublicKey.getInstance(encodedPubKey);
SubjectPublicKeyInfo info = SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(new RSAKeyParameters(false, pubKey8.getModulus(), pubKey8.getPublicExponent()));
X509EncodedKeySpec spec = new X509EncodedKeySpec(info.getEncoded());
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return keyFactory.generatePublic(spec);
}

/**
* Decode based on d - 32 byte integer
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.Provider;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.cert.X509Certificate;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.MGF1ParameterSpec;
import java.security.spec.PSSParameterSpec;

Expand All @@ -46,25 +48,36 @@ public static boolean verify(X509Certificate x509Certificate,
}

public static byte[] sign(PrivateKey privateKey,
byte[] signedDate) throws SignatureException,
byte[] signedData) throws SignatureException,
InvalidKeyException, NoSuchAlgorithmException,
NoSuchProviderException, InvalidAlgorithmParameterException {
Signature signature = Signature.getInstance("SHA256withRSA", BC);
signature.initSign(privateKey);
signature.update(signedDate);
signature.update(signedData);
return signature.sign();
}

public static boolean verifyPSS(X509Certificate x509Certificate,
byte[] signedDate, byte[] sig) throws SignatureException,
public static byte[] signPSS(PrivateKey privateKey,
byte[] signedData) throws SignatureException,
InvalidKeyException, NoSuchAlgorithmException,
NoSuchProviderException, InvalidAlgorithmParameterException {
Signature signature = Signature.getInstance("RAWRSASSA-PSS", BC);
Signature signature = Signature.getInstance("SHA256withRSA/PSS", BC);
signature.setParameter(new PSSParameterSpec("SHA-256", "MGF1",
new MGF1ParameterSpec("SHA-256"), 32, 1));
signature.initVerify(x509Certificate.getPublicKey());
signature.update(signedDate);
//signature.update(SHA.sha(signedDate, "SHA-256"));
signature.initSign(privateKey);
signature.update(signedData);
return signature.sign();
}

public static boolean verifyPSS(PublicKey publicKey,
byte[] signedData, byte[] sig) throws SignatureException,
InvalidKeyException, NoSuchAlgorithmException,
NoSuchProviderException, InvalidAlgorithmParameterException, InvalidKeySpecException {
Signature signature = Signature.getInstance("SHA256withRSA/PSS", BC);
signature.setParameter(new PSSParameterSpec("SHA-256", "MGF1",
new MGF1ParameterSpec("SHA-256"), 32, 1));
signature.initVerify(publicKey);
signature.update(signedData);
return signature.verify(sig);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,19 @@
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PublicKey;
import java.security.SignatureException;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.jce.interfaces.ECPublicKey;
import org.ebayopensource.fido.uaf.crypto.Asn1;
import org.ebayopensource.fido.uaf.crypto.KeyCodec;
import org.ebayopensource.fido.uaf.crypto.NamedCurve;
import org.ebayopensource.fido.uaf.crypto.Notary;
import org.ebayopensource.fido.uaf.crypto.RSA;
import org.ebayopensource.fido.uaf.crypto.SHA;
import org.ebayopensource.fido.uaf.msg.AuthenticationResponse;
import org.ebayopensource.fido.uaf.msg.AuthenticatorSignAssertion;
Expand All @@ -40,11 +43,11 @@
import org.ebayopensource.fido.uaf.storage.AuthenticatorRecord;
import org.ebayopensource.fido.uaf.storage.RegistrationRecord;
import org.ebayopensource.fido.uaf.storage.StorageInterface;
import org.ebayopensource.fido.uaf.tlv.AlgAndEncodingEnum;
import org.ebayopensource.fido.uaf.tlv.Tag;
import org.ebayopensource.fido.uaf.tlv.Tags;
import org.ebayopensource.fido.uaf.tlv.TagsEnum;
import org.ebayopensource.fido.uaf.tlv.TlvAssertionParser;
import org.ebayopensource.fido.uaf.tlv.AlgAndEncodingEnum;

public class AuthenticationResponseProcessing {

Expand Down Expand Up @@ -99,27 +102,21 @@ private AuthenticatorRecord processAssertions(
Tag info = tags.getTags().get(TagsEnum.TAG_ASSERTION_INFO.id);
AlgAndEncodingEnum algAndEncoding = getAlgAndEncoding(info);
String pubKey = registrationRecord.PublicKey;
if (algAndEncoding == AlgAndEncodingEnum.UAF_ALG_SIGN_RSASSA_PSS_SHA256_DER) {
// TODO Implement RSA signature check
authRecord.status = "FAILED_ALGORITHM_NOT_IMPLEMENTED";
return authRecord;
} else {
try {
if (!verifySignature(signnedData, signature, pubKey,
algAndEncoding)) {
logger.log(Level.INFO,
"Signature verification failed for authenticator: "
+ authRecord.toString());
authRecord.status = "FAILED_SIGNATURE_NOT_VALID";
return authRecord;
}
} catch (Exception e) {
try {
if (!verifySignature(signnedData, signature, pubKey,
algAndEncoding)) {
logger.log(Level.INFO,
"Signature verification failed for authenticator: "
+ authRecord.toString(), e);
authRecord.status = "FAILED_SIGNATURE_VERIFICATION";
+ authRecord.toString());
authRecord.status = "FAILED_SIGNATURE_NOT_VALID";
return authRecord;
}
} catch (Exception e) {
logger.log(Level.INFO,
"Signature verification failed for authenticator: "
+ authRecord.toString(), e);
authRecord.status = "FAILED_SIGNATURE_VERIFICATION";
return authRecord;
}
authRecord.username = registrationRecord.username;
authRecord.deviceId = registrationRecord.deviceId;
Expand Down Expand Up @@ -166,45 +163,57 @@ private boolean verifySignature(Tag signedData, Tag signature,
// dataForSigning, Asn1.decodeToBigIntegerArray(signature.value));

byte[] decodeBase64 = Base64.decodeBase64(pubKey);
if (algAndEncoding == AlgAndEncodingEnum.UAF_ALG_SIGN_SECP256K1_ECDSA_SHA256_DER) {
ECPublicKey decodedPub = (ECPublicKey) KeyCodec.getPubKeyFromCurve(
decodeBase64, "secp256k1");
return NamedCurve.verifyUsingSecp256k1(
KeyCodec.getKeyAsRawBytes(decodedPub),
SHA.sha(dataForSigning, "SHA-256"),
Asn1.decodeToBigIntegerArray(signature.value));
}
if (algAndEncoding == AlgAndEncodingEnum.UAF_ALG_SIGN_SECP256R1_ECDSA_SHA256_DER) {
if (decodeBase64.length>65){
return NamedCurve.verify(KeyCodec.getKeyAsRawBytes(pubKey),
if(algAndEncoding == AlgAndEncodingEnum.UAF_ALG_SIGN_RSASSA_PSS_SHA256_RAW) {
PublicKey publicKey = KeyCodec.getRSAPublicKey(decodeBase64);
return RSA.verifyPSS(publicKey,
SHA.sha(dataForSigning, "SHA-256"),
signature.value);
} else if(algAndEncoding == AlgAndEncodingEnum.UAF_ALG_SIGN_RSASSA_PSS_SHA256_DER) {
PublicKey publicKey = KeyCodec.getRSAPublicKey(new DEROctetString(decodeBase64).getOctets());
return RSA.verifyPSS(publicKey,
SHA.sha(dataForSigning, "SHA-256"),
new DEROctetString(signature.value).getOctets());
} else {
if (algAndEncoding == AlgAndEncodingEnum.UAF_ALG_SIGN_SECP256K1_ECDSA_SHA256_DER) {
ECPublicKey decodedPub = (ECPublicKey) KeyCodec.getPubKeyFromCurve(
decodeBase64, "secp256k1");
return NamedCurve.verifyUsingSecp256k1(
KeyCodec.getKeyAsRawBytes(decodedPub),
SHA.sha(dataForSigning, "SHA-256"),
Asn1.decodeToBigIntegerArray(signature.value));
} else {
}
if (algAndEncoding == AlgAndEncodingEnum.UAF_ALG_SIGN_SECP256R1_ECDSA_SHA256_DER) {
if (decodeBase64.length>65){
return NamedCurve.verify(KeyCodec.getKeyAsRawBytes(pubKey),
SHA.sha(dataForSigning, "SHA-256"),
Asn1.decodeToBigIntegerArray(signature.value));
} else {
ECPublicKey decodedPub = (ECPublicKey) KeyCodec.getPubKeyFromCurve(
decodeBase64, "secp256r1");
return NamedCurve.verify(KeyCodec.getKeyAsRawBytes(decodedPub),
SHA.sha(dataForSigning, "SHA-256"),
Asn1.decodeToBigIntegerArray(signature.value));
}
}
if (signature.value.length == 64) {
ECPublicKey decodedPub = (ECPublicKey) KeyCodec.getPubKeyFromCurve(
decodeBase64, "secp256r1");
return NamedCurve.verify(KeyCodec.getKeyAsRawBytes(decodedPub),
SHA.sha(dataForSigning, "SHA-256"),
Asn1.decodeToBigIntegerArray(signature.value));
SHA.sha(dataForSigning, "SHA-256"),
Asn1.transformRawSignature(signature.value));
} else if (65 == decodeBase64.length
&& AlgAndEncodingEnum.UAF_ALG_SIGN_SECP256R1_ECDSA_SHA256_DER == algAndEncoding) {
ECPublicKey decodedPub = (ECPublicKey) KeyCodec.getPubKeyFromCurve(
decodeBase64, "secp256r1");
return NamedCurve.verify(KeyCodec.getKeyAsRawBytes(decodedPub),
SHA.sha(dataForSigning, "SHA-256"),
Asn1.decodeToBigIntegerArray(signature.value));
} else {
return NamedCurve.verify(KeyCodec.getKeyAsRawBytes(pubKey),
SHA.sha(dataForSigning, "SHA-256"),
Asn1.decodeToBigIntegerArray(signature.value));
}
}
if (signature.value.length == 64) {
ECPublicKey decodedPub = (ECPublicKey) KeyCodec.getPubKeyFromCurve(
decodeBase64, "secp256r1");
return NamedCurve.verify(KeyCodec.getKeyAsRawBytes(decodedPub),
SHA.sha(dataForSigning, "SHA-256"),
Asn1.transformRawSignature(signature.value));
} else if (65 == decodeBase64.length
&& AlgAndEncodingEnum.UAF_ALG_SIGN_SECP256R1_ECDSA_SHA256_DER == algAndEncoding) {
ECPublicKey decodedPub = (ECPublicKey) KeyCodec.getPubKeyFromCurve(
decodeBase64, "secp256r1");
return NamedCurve.verify(KeyCodec.getKeyAsRawBytes(decodedPub),
SHA.sha(dataForSigning, "SHA-256"),
Asn1.decodeToBigIntegerArray(signature.value));
} else {
return NamedCurve.verify(KeyCodec.getKeyAsRawBytes(pubKey),
SHA.sha(dataForSigning, "SHA-256"),
Asn1.decodeToBigIntegerArray(signature.value));
}
}

private byte[] getDataForSigning(Tag signedData) throws IOException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,12 @@ public enum AlgAndEncodingEnum {

UAF_ALG_SIGN_SECP256R1_ECDSA_SHA256_RAW (0x01),
UAF_ALG_SIGN_SECP256R1_ECDSA_SHA256_DER (0x02),
UAF_ALG_SIGN_RSASSA_PSS_SHA256_RAW(0x03),
UAF_ALG_SIGN_RSASSA_PSS_SHA256_DER (0x04),
UAF_ALG_KEY_ECC_X962_RAW (0x100),
UAF_ALG_KEY_ECC_X962_DER (0x101),
UAF_ALG_KEY_RSA_2048_PSS_RAW(0x102),
UAF_ALG_KEY_RSA_2048_PSS_DER(0x103),
UAF_ALG_SIGN_SECP256K1_ECDSA_SHA256_DER (0x06)
;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,27 @@

import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.interfaces.RSAPrivateKey;
import java.security.SignatureException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import java.util.logging.Logger;

import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.crypto.CryptoException;
import org.bouncycastle.crypto.DataLengthException;
import org.bouncycastle.crypto.digests.SHA256Digest;
import org.bouncycastle.crypto.engines.RSAEngine;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.crypto.params.RSAKeyParameters;
import org.bouncycastle.crypto.signers.PSSSigner;
import org.bouncycastle.util.encoders.Hex;
import org.junit.Assert;
import org.junit.Test;

public class KeyCodecTest {
Expand Down Expand Up @@ -58,15 +56,65 @@ public void test() throws InvalidAlgorithmParameterException,
}

@Test
public void pss() throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchProviderException, DataLengthException, CryptoException{
public void pss() throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchProviderException, DataLengthException, CryptoException, InvalidKeyException, SignatureException, InvalidKeySpecException, IOException{
KeyPair keyPair = KeyCodec.getRSAKeyPair();
RSAKeyParameters privateKeyParameter = KeyCodec.generatePrivateKeyParameter((RSAPrivateKey)keyPair.getPrivate());
byte[] slt = Hex.decode("dee959c7e06411361420ff80185ed57f3e6776af"); //a random salt
PSSSigner eng = new PSSSigner(new RSAEngine(), new SHA256Digest(), 20); //creation of PssSigner
eng.init(true, new ParametersWithRandom(privateKeyParameter , new SecureRandom(slt))); //initiation of PssSigner
eng.update(slt, 0, slt.length);
byte[] signed = eng.generateSignature();
KeyPair keyPair2 = KeyCodec.getRSAKeyPair();

PrivateKey privKey = keyPair.getPrivate();
byte[] encodedPrivKey = privKey.getEncoded();
logger.info("priv=" + Base64.encodeBase64URLSafeString(encodedPrivKey));

PublicKey pubKey = keyPair.getPublic();
byte[] encodedPubKey = pubKey.getEncoded();
SubjectPublicKeyInfo spkInfo = SubjectPublicKeyInfo.getInstance(encodedPubKey);
ASN1Primitive primitive = spkInfo.parsePublicKey();

PublicKey publicKey = KeyCodec.getRSAPublicKey(primitive.getEncoded());
logger.info("pub=" + Base64.encodeBase64URLSafeString(encodedPubKey));
logger.info("pub format=" + pubKey.getFormat());
logger.info("pub alg=" + pubKey.getAlgorithm());

byte[] slt = Hex.decode("dee959c7e06411361420ff80185ed57f3e6776af"); //a random salt

byte[] signed = RSA.signPSS(privKey, slt);
assertTrue(signed.length>0);
RSA rsa = new RSA();
Assert.assertTrue(rsa.verifyPSS(publicKey, slt, signed));
byte[] slt2 = Hex.decode("dee959c7e06411361420ff80185ed57f3e6776aa"); //a random salt

byte[] signed2 = RSA.signPSS(keyPair2.getPrivate(), slt2);
Assert.assertFalse(rsa.verifyPSS(publicKey, slt2, signed2));
Assert.assertFalse(rsa.verifyPSS(keyPair2.getPublic(), slt, signed));
}

@Test
public void pssDER() throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchProviderException, DataLengthException, CryptoException, InvalidKeyException, SignatureException, InvalidKeySpecException, IOException{
KeyPair keyPair = KeyCodec.getRSAKeyPair();
KeyPair keyPair2 = KeyCodec.getRSAKeyPair();

PrivateKey privKey = keyPair.getPrivate();
byte[] encodedPrivKey = privKey.getEncoded();
logger.info("priv=" + Base64.encodeBase64URLSafeString(encodedPrivKey));

PublicKey pubKey = keyPair.getPublic();
byte[] encodedPubKey = pubKey.getEncoded();

logger.info("pub=" + Base64.encodeBase64URLSafeString(encodedPubKey));
logger.info("pub format=" + pubKey.getFormat());
logger.info("pub alg=" + pubKey.getAlgorithm());

byte[] slt = Hex.decode("dee959c7e06411361420ff80185ed57f3e6776af"); //a random salt

byte[] signed = RSA.signPSS(privKey, slt);

assertTrue(signed.length>0);
RSA rsa = new RSA();
Assert.assertTrue(rsa.verifyPSS(pubKey, slt, signed));
byte[] slt2 = Hex.decode("dee959c7e06411361420ff80185ed57f3e6776aa"); //a random salt

byte[] signed2 = RSA.signPSS(keyPair2.getPrivate(), slt2);
Assert.assertFalse(rsa.verifyPSS(pubKey, slt2, signed2));
Assert.assertFalse(rsa.verifyPSS(keyPair2.getPublic(), slt, signed));
}

}

0 comments on commit a3fa311

Please sign in to comment.