open-keychain/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/EcObjectIdentifiers.java
2021-03-16 17:07:56 +01:00

72 lines
3.3 KiB
Java

package org.sufficientlysecure.keychain.securitytoken;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.cryptlib.CryptlibObjectIdentifiers;
import org.bouncycastle.asn1.gnu.GNUObjectIdentifiers;
import org.bouncycastle.asn1.sec.SECObjectIdentifiers;
import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import timber.log.Timber;
public class EcObjectIdentifiers {
public static final ASN1ObjectIdentifier NIST_P_256 = SECObjectIdentifiers.secp256r1;
public static final ASN1ObjectIdentifier NIST_P_384 = SECObjectIdentifiers.secp384r1;
public static final ASN1ObjectIdentifier NIST_P_521 = SECObjectIdentifiers.secp521r1;
public static final ASN1ObjectIdentifier BRAINPOOL_P256_R1 = TeleTrusTObjectIdentifiers.brainpoolP256r1;
public static final ASN1ObjectIdentifier BRAINPOOL_P512_R1 = TeleTrusTObjectIdentifiers.brainpoolP512r1;
public static final ASN1ObjectIdentifier ED25519 = GNUObjectIdentifiers.Ed25519; // for use with EdDSA
public static final ASN1ObjectIdentifier X25519 = CryptlibObjectIdentifiers.curvey25519; // for use with ECDH
public static HashSet<ASN1ObjectIdentifier> sOids = new HashSet<>(Arrays.asList(
NIST_P_256, NIST_P_384, NIST_P_521, BRAINPOOL_P256_R1, BRAINPOOL_P512_R1, ED25519, X25519
));
public static ASN1ObjectIdentifier parseOid(byte[] oidField) {
ASN1ObjectIdentifier asn1CurveOid = oidFieldToOidAsn1(oidField);
if (sOids.contains(asn1CurveOid)) {
return asn1CurveOid;
}
Timber.w("Unknown curve OID: %s. Could be YubiKey firmware bug < 5.2.8. Trying again with last byte removed.", asn1CurveOid.getId());
// https://bugs.chromium.org/p/chromium/issues/detail?id=1120933#c10
// The OpenPGP applet of a Yubikey with firmware version below 5.2.8 appends
// a potentially arbitrary byte to the intended byte representation of an ECC
// curve OID. This case is handled by retrying the decoding with the last
// byte stripped if the resulting OID does not label a known curve.
byte[] oidRemoveLastByte = Arrays.copyOf(oidField, oidField.length - 1);
ASN1ObjectIdentifier asn1CurveOidYubikey = oidFieldToOidAsn1(oidRemoveLastByte);
if (sOids.contains(asn1CurveOidYubikey)) {
Timber.w("Detected curve OID: %s", asn1CurveOidYubikey.getId());
} else {
Timber.e("Still Unknown curve OID: %s", asn1CurveOidYubikey.getId());
}
return asn1CurveOidYubikey;
}
public static byte[] asn1ToOidField(ASN1ObjectIdentifier oidAsn1) {
byte[] encodedAsn1Oid;
try {
encodedAsn1Oid = oidAsn1.getEncoded();
} catch (IOException e) {
throw new IllegalStateException("Failed to encode curve OID!");
}
byte[] oidField = new byte[encodedAsn1Oid.length - 2];
System.arraycopy(encodedAsn1Oid, 2, oidField, 0, encodedAsn1Oid.length - 2);
return oidField;
}
public static ASN1ObjectIdentifier oidFieldToOidAsn1(byte[] oidField) {
final byte[] boid = new byte[2 + oidField.length];
boid[0] = (byte) 0x06;
boid[1] = (byte) oidField.length;
System.arraycopy(oidField, 0, boid, 2, oidField.length);
return ASN1ObjectIdentifier.getInstance(boid);
}
}