Skip to content

Commit a71a9cd

Browse files
committed
Add support for RSA keys
1 parent 181f969 commit a71a9cd

File tree

5 files changed

+39
-5
lines changed

5 files changed

+39
-5
lines changed

NEWS

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
== Version 1.1.1 (unreleased) ==
1+
== Version 1.2.0 (unreleased) ==
2+
3+
New features:
4+
5+
* RSA keys are now supported.
26

37
Bug fixes:
48

webauthn-server-core/src/main/java/com/yubico/internal/util/WebAuthnCodecs.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,17 @@
3838
import com.yubico.webauthn.data.ByteArray;
3939
import com.yubico.webauthn.data.COSEAlgorithmIdentifier;
4040
import java.io.IOException;
41+
import java.math.BigInteger;
42+
import java.security.KeyFactory;
43+
import java.security.NoSuchAlgorithmException;
4144
import java.security.PublicKey;
4245
import java.security.interfaces.ECPublicKey;
46+
import java.security.spec.InvalidKeySpecException;
47+
import java.security.spec.RSAPublicKeySpec;
4348
import java.util.Arrays;
4449
import java.util.HashMap;
4550
import java.util.Map;
51+
import org.bouncycastle.jce.provider.BouncyCastleProvider;
4652

4753

4854
public final class WebAuthnCodecs {
@@ -123,16 +129,25 @@ public static ByteArray ecPublicKeyToCose(ECPublicKey key) {
123129
return rawEcdaKeyToCose(ecPublicKeyToRaw(key));
124130
}
125131

126-
public static PublicKey importCosePublicKey(ByteArray key) throws CoseException, IOException {
132+
public static PublicKey importCosePublicKey(ByteArray key) throws CoseException, IOException, InvalidKeySpecException, NoSuchAlgorithmException {
127133
CBORObject cose = CBORObject.DecodeFromBytes(key.getBytes());
128134
final int kty = cose.get(CBORObject.FromObject(1)).AsInt32();
129135
switch (kty) {
130136
case 2: return importCoseP256PublicKey(cose);
137+
case 3: return importCoseRsaPublicKey(cose);
131138
default:
132139
throw new IllegalArgumentException("Unsupported key type: " + kty);
133140
}
134141
}
135142

143+
private static PublicKey importCoseRsaPublicKey(CBORObject cose) throws NoSuchAlgorithmException, InvalidKeySpecException {
144+
RSAPublicKeySpec spec = new RSAPublicKeySpec(
145+
new BigInteger(1, cose.get(CBORObject.FromObject(-1)).GetByteString()),
146+
new BigInteger(1, cose.get(CBORObject.FromObject(-2)).GetByteString())
147+
);
148+
return KeyFactory.getInstance("RSA", new BouncyCastleProvider()).generatePublic(spec);
149+
}
150+
136151
private static ECPublicKey importCoseP256PublicKey(CBORObject cose) throws CoseException, IOException {
137152
return new COSE.ECPublicKey(new OneKey(cose));
138153
}

webauthn-server-core/src/main/java/com/yubico/webauthn/FidoU2fAttestationStatementVerifier.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,18 +26,21 @@
2626

2727
import COSE.CoseException;
2828
import com.fasterxml.jackson.databind.JsonNode;
29+
import com.yubico.internal.util.ExceptionUtil;
2930
import com.yubico.internal.util.WebAuthnCodecs;
3031
import com.yubico.webauthn.data.AttestationObject;
3132
import com.yubico.webauthn.data.AttestationType;
3233
import com.yubico.webauthn.data.AttestedCredentialData;
3334
import com.yubico.webauthn.data.ByteArray;
3435
import java.io.IOException;
3536
import java.math.BigInteger;
37+
import java.security.NoSuchAlgorithmException;
3638
import java.security.PublicKey;
3739
import java.security.cert.CertificateException;
3840
import java.security.cert.X509Certificate;
3941
import java.security.interfaces.ECPublicKey;
4042
import java.security.spec.ECParameterSpec;
43+
import java.security.spec.InvalidKeySpecException;
4144
import java.util.Objects;
4245
import java.util.Optional;
4346
import lombok.extern.slf4j.Slf4j;
@@ -83,7 +86,12 @@ private static boolean validSelfSignature(X509Certificate cert) {
8386

8487
private static ByteArray getRawUserPublicKey(AttestationObject attestationObject) throws IOException, CoseException {
8588
final ByteArray pubkeyCose = attestationObject.getAuthenticatorData().getAttestedCredentialData().get().getCredentialPublicKey();
86-
final PublicKey pubkey = WebAuthnCodecs.importCosePublicKey(pubkeyCose);
89+
final PublicKey pubkey;
90+
try {
91+
pubkey = WebAuthnCodecs.importCosePublicKey(pubkeyCose);
92+
} catch (InvalidKeySpecException | NoSuchAlgorithmException e) {
93+
throw ExceptionUtil.wrapAndLog(log, "Failed to decode public key: " + pubkeyCose.getHex(), e);
94+
}
8795

8896
final ECPublicKey ecPubkey;
8997
try {

webauthn-server-core/src/main/java/com/yubico/webauthn/FinishAssertionSteps.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@
3737
import com.yubico.webauthn.exception.InvalidSignatureCountException;
3838
import com.yubico.webauthn.extension.appid.AppId;
3939
import java.io.IOException;
40+
import java.security.NoSuchAlgorithmException;
4041
import java.security.PublicKey;
42+
import java.security.spec.InvalidKeySpecException;
4143
import java.util.ArrayList;
4244
import java.util.Collections;
4345
import java.util.LinkedList;
@@ -547,7 +549,7 @@ public void validate() {
547549

548550
try {
549551
key = WebAuthnCodecs.importCosePublicKey(cose);
550-
} catch (CoseException | IOException e) {
552+
} catch (CoseException | IOException | InvalidKeySpecException e) {
551553
throw new IllegalArgumentException(
552554
String.format(
553555
"Failed to decode public key: Credential ID: %s COSE: %s",
@@ -556,6 +558,8 @@ public void validate() {
556558
),
557559
e
558560
);
561+
} catch (NoSuchAlgorithmException e) {
562+
throw new RuntimeException(e);
559563
}
560564

561565
if (!

webauthn-server-core/src/main/java/com/yubico/webauthn/PackedAttestationStatementVerifier.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
import java.security.SignatureException;
4747
import java.security.cert.CertificateException;
4848
import java.security.cert.X509Certificate;
49+
import java.security.spec.InvalidKeySpecException;
4950
import java.util.Arrays;
5051
import java.util.HashSet;
5152
import java.util.Locale;
@@ -101,12 +102,14 @@ private boolean verifySelfAttestationSignature(AttestationObject attestationObje
101102
pubkey = WebAuthnCodecs.importCosePublicKey(
102103
attestationObject.getAuthenticatorData().getAttestedCredentialData().get().getCredentialPublicKey()
103104
);
104-
} catch (IOException | CoseException e) {
105+
} catch (IOException | CoseException | InvalidKeySpecException e) {
105106
throw ExceptionUtil.wrapAndLog(
106107
log,
107108
String.format("Failed to parse public key from attestation data %s", attestationObject.getAuthenticatorData().getAttestedCredentialData()),
108109
e
109110
);
111+
} catch (NoSuchAlgorithmException e) {
112+
throw new RuntimeException(e);
110113
}
111114

112115
final Long keyAlgId = CBORObject.DecodeFromBytes(attestationObject.getAuthenticatorData().getAttestedCredentialData().get().getCredentialPublicKey().getBytes())

0 commit comments

Comments
 (0)