From 0546c20c9d97bdef336d7cfad4d03a7621b07fc0 Mon Sep 17 00:00:00 2001 From: Kees Geluk Date: Fri, 27 Oct 2023 16:19:55 +0200 Subject: [PATCH 1/2] Conversion of package appverifier > readercertgen to Kotlin --- .../readercertgen/CertificateGenerator.java | 113 -------------- .../readercertgen/CertificateGenerator.kt | 108 ++++++++++++++ .../readercertgen/CertificateMaterial.java | 21 --- .../readercertgen/CertificateMaterial.kt | 18 +++ .../appreader/readercertgen/DataMaterial.java | 12 -- .../appreader/readercertgen/DataMaterial.kt | 9 ++ .../appreader/readercertgen/EncodingUtil.java | 24 --- .../appreader/readercertgen/EncodingUtil.kt | 17 +++ .../appreader/readercertgen/KeyMaterial.java | 17 --- .../appreader/readercertgen/KeyMaterial.kt | 13 ++ .../ReaderCertificateGenerator.java | 139 ------------------ .../ReaderCertificateGenerator.kt | 87 +++++++++++ ...upportedCurves.java => SupportedCurves.kt} | 6 +- 13 files changed, 255 insertions(+), 329 deletions(-) delete mode 100644 appverifier/src/main/java/com/android/mdl/appreader/readercertgen/CertificateGenerator.java create mode 100644 appverifier/src/main/java/com/android/mdl/appreader/readercertgen/CertificateGenerator.kt delete mode 100644 appverifier/src/main/java/com/android/mdl/appreader/readercertgen/CertificateMaterial.java create mode 100644 appverifier/src/main/java/com/android/mdl/appreader/readercertgen/CertificateMaterial.kt delete mode 100644 appverifier/src/main/java/com/android/mdl/appreader/readercertgen/DataMaterial.java create mode 100644 appverifier/src/main/java/com/android/mdl/appreader/readercertgen/DataMaterial.kt delete mode 100644 appverifier/src/main/java/com/android/mdl/appreader/readercertgen/EncodingUtil.java create mode 100644 appverifier/src/main/java/com/android/mdl/appreader/readercertgen/EncodingUtil.kt delete mode 100644 appverifier/src/main/java/com/android/mdl/appreader/readercertgen/KeyMaterial.java create mode 100644 appverifier/src/main/java/com/android/mdl/appreader/readercertgen/KeyMaterial.kt delete mode 100644 appverifier/src/main/java/com/android/mdl/appreader/readercertgen/ReaderCertificateGenerator.java create mode 100644 appverifier/src/main/java/com/android/mdl/appreader/readercertgen/ReaderCertificateGenerator.kt rename appverifier/src/main/java/com/android/mdl/appreader/readercertgen/{SupportedCurves.java => SupportedCurves.kt} (61%) diff --git a/appverifier/src/main/java/com/android/mdl/appreader/readercertgen/CertificateGenerator.java b/appverifier/src/main/java/com/android/mdl/appreader/readercertgen/CertificateGenerator.java deleted file mode 100644 index 57a79613c..000000000 --- a/appverifier/src/main/java/com/android/mdl/appreader/readercertgen/CertificateGenerator.java +++ /dev/null @@ -1,113 +0,0 @@ -package com.android.mdl.appreader.readercertgen; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.x500.X500Name; -import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier; -import org.bouncycastle.asn1.x509.BasicConstraints; -import org.bouncycastle.asn1.x509.ExtendedKeyUsage; -import org.bouncycastle.asn1.x509.Extension; -import org.bouncycastle.asn1.x509.GeneralName; -import org.bouncycastle.asn1.x509.GeneralNames; -import org.bouncycastle.asn1.x509.KeyPurposeId; -import org.bouncycastle.asn1.x509.KeyUsage; -import org.bouncycastle.asn1.x509.SubjectKeyIdentifier; -import org.bouncycastle.cert.CertIOException; -import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; -import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils; -import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder; -import org.bouncycastle.jce.provider.BouncyCastleProvider; -import org.bouncycastle.operator.ContentSigner; -import org.bouncycastle.operator.OperatorCreationException; -import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; - -import java.io.IOException; -import java.security.NoSuchAlgorithmException; -import java.security.Provider; -import java.security.Security; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; -import java.util.Optional; - -public final class CertificateGenerator { - private static final boolean CRITICAL = true; - private static final boolean NOT_CRITICAL = false; - - private CertificateGenerator() { - // avoid instantiation - } - - static X509Certificate generateCertificate(DataMaterial data, CertificateMaterial certMaterial, KeyMaterial keyMaterial) - throws CertIOException, CertificateException, OperatorCreationException { - - Optional issuerCert = keyMaterial.issuerCertificate(); - - X500Name subjectDN = new X500Name(data.subjectDN()); - // doesn't work, get's reordered - // issuerCert.isPresent() ? new X500Name(issuerCert.get().getSubjectX500Principal().getName()) : subjectDN; - X500Name issuerDN = new X500Name(data.issuerDN()); - - ContentSigner contentSigner = new JcaContentSignerBuilder(keyMaterial.signingAlgorithm()).build(keyMaterial.signingKey()); - - JcaX509v3CertificateBuilder certBuilder = new JcaX509v3CertificateBuilder( - issuerDN, - certMaterial.serialNumber(), - certMaterial.startDate(), certMaterial.endDate(), - subjectDN, - keyMaterial.publicKey()); - - - // Extensions -------------------------- - - JcaX509ExtensionUtils jcaX509ExtensionUtils; - try { - jcaX509ExtensionUtils = new JcaX509ExtensionUtils(); - } catch (NoSuchAlgorithmException e) { - throw new RuntimeException(e); - } - - - if (issuerCert.isPresent()) { - try { - // adds 3 more fields, not present in other cert - // AuthorityKeyIdentifier authorityKeyIdentifier = jcaX509ExtensionUtils.createAuthorityKeyIdentifier(issuerCert.get()); - AuthorityKeyIdentifier authorityKeyIdentifier = jcaX509ExtensionUtils.createAuthorityKeyIdentifier(issuerCert.get().getPublicKey()); - certBuilder.addExtension(Extension.authorityKeyIdentifier, NOT_CRITICAL, authorityKeyIdentifier); - } catch (IOException e) { // CertificateEncodingException | - throw new RuntimeException(e); - } - } - - SubjectKeyIdentifier subjectKeyIdentifier = jcaX509ExtensionUtils.createSubjectKeyIdentifier(keyMaterial.publicKey()); - certBuilder.addExtension(Extension.subjectKeyIdentifier, NOT_CRITICAL, subjectKeyIdentifier); - - KeyUsage keyUsage = new KeyUsage(certMaterial.keyUsage()); - certBuilder.addExtension(Extension.keyUsage, CRITICAL, keyUsage); - - // IssuerAlternativeName - Optional issuerAlternativeName = data.issuerAlternativeName(); - if (issuerAlternativeName.isPresent()) { - GeneralNames issuerAltName = new GeneralNames(new GeneralName(GeneralName.uniformResourceIdentifier, issuerAlternativeName.get())); - certBuilder.addExtension(Extension.issuerAlternativeName, NOT_CRITICAL, issuerAltName); - } - - // Basic Constraints - int pathLengthConstraint = certMaterial.pathLengthConstraint(); - if (pathLengthConstraint != CertificateMaterial.PATHLENGTH_NOT_A_CA) { - // TODO doesn't work for certificate chains != 2 in size - BasicConstraints basicConstraints = new BasicConstraints(pathLengthConstraint); - certBuilder.addExtension(Extension.basicConstraints, CRITICAL, basicConstraints); - } - - Optional extendedKeyUsage = certMaterial.extendedKeyUsage(); - if (extendedKeyUsage.isPresent()) { - KeyPurposeId keyPurpose = KeyPurposeId.getInstance(new ASN1ObjectIdentifier(extendedKeyUsage.get())); - ExtendedKeyUsage extKeyUsage = new ExtendedKeyUsage(new KeyPurposeId[]{keyPurpose}); - certBuilder.addExtension(Extension.extendedKeyUsage, CRITICAL, extKeyUsage); - } - - // DEBUG setProvider(bcProvider) removed before getCertificate - return new JcaX509CertificateConverter().getCertificate(certBuilder.build(contentSigner)); - } - - -} diff --git a/appverifier/src/main/java/com/android/mdl/appreader/readercertgen/CertificateGenerator.kt b/appverifier/src/main/java/com/android/mdl/appreader/readercertgen/CertificateGenerator.kt new file mode 100644 index 000000000..0eece90e4 --- /dev/null +++ b/appverifier/src/main/java/com/android/mdl/appreader/readercertgen/CertificateGenerator.kt @@ -0,0 +1,108 @@ +package com.android.mdl.appreader.readercertgen + +import org.bouncycastle.asn1.ASN1ObjectIdentifier +import org.bouncycastle.asn1.x500.X500Name +import org.bouncycastle.asn1.x509.BasicConstraints +import org.bouncycastle.asn1.x509.ExtendedKeyUsage +import org.bouncycastle.asn1.x509.Extension +import org.bouncycastle.asn1.x509.GeneralName +import org.bouncycastle.asn1.x509.GeneralNames +import org.bouncycastle.asn1.x509.KeyPurposeId +import org.bouncycastle.asn1.x509.KeyUsage +import org.bouncycastle.asn1.x509.SubjectKeyIdentifier +import org.bouncycastle.cert.CertIOException +import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter +import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils +import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder +import org.bouncycastle.operator.OperatorCreationException +import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder +import java.io.IOException +import java.security.NoSuchAlgorithmException +import java.security.cert.CertificateException +import java.security.cert.X509Certificate +import java.util.Optional + +object CertificateGenerator { + private const val CRITICAL = true + private const val NOT_CRITICAL = false + @JvmStatic + @Throws(CertIOException::class, CertificateException::class, OperatorCreationException::class) + fun generateCertificate( + data: DataMaterial, + certMaterial: CertificateMaterial, + keyMaterial: KeyMaterial + ): X509Certificate { + val issuerCert: Optional = keyMaterial.issuerCertificate + val subjectDN = X500Name(data.subjectDN) + // doesn't work, get's reordered + // issuerCert.isPresent() ? new X500Name(issuerCert.get().getSubjectX500Principal().getName()) : subjectDN; + val issuerDN = X500Name(data.issuerDN) + val contentSigner = + JcaContentSignerBuilder(keyMaterial.signingAlgorithm).build(keyMaterial.signingKey) + val certBuilder = JcaX509v3CertificateBuilder( + issuerDN, + certMaterial.serialNumber, + certMaterial.startDate, certMaterial.endDate, + subjectDN, + keyMaterial.publicKey + ) + + + // Extensions -------------------------- + val jcaX509ExtensionUtils: JcaX509ExtensionUtils + jcaX509ExtensionUtils = try { + JcaX509ExtensionUtils() + } catch (e: NoSuchAlgorithmException) { + throw RuntimeException(e) + } + if (issuerCert.isPresent) { + try { + // adds 3 more fields, not present in other cert + // AuthorityKeyIdentifier authorityKeyIdentifier = jcaX509ExtensionUtils.createAuthorityKeyIdentifier(issuerCert.get()); + val authorityKeyIdentifier = + jcaX509ExtensionUtils.createAuthorityKeyIdentifier(issuerCert.get().publicKey) + certBuilder.addExtension( + Extension.authorityKeyIdentifier, + NOT_CRITICAL, + authorityKeyIdentifier + ) + } catch (e: IOException) { // CertificateEncodingException | + throw RuntimeException(e) + } + } + val subjectKeyIdentifier: SubjectKeyIdentifier = + jcaX509ExtensionUtils.createSubjectKeyIdentifier(keyMaterial.publicKey) + certBuilder.addExtension(Extension.subjectKeyIdentifier, NOT_CRITICAL, subjectKeyIdentifier) + val keyUsage = KeyUsage(certMaterial.keyUsage) + certBuilder.addExtension(Extension.keyUsage, CRITICAL, keyUsage) + + // IssuerAlternativeName + val issuerAlternativeName: Optional = data.issuerAlternativeName + if (issuerAlternativeName.isPresent) { + val issuerAltName = GeneralNames( + GeneralName( + GeneralName.uniformResourceIdentifier, + issuerAlternativeName.get() + ) + ) + certBuilder.addExtension(Extension.issuerAlternativeName, NOT_CRITICAL, issuerAltName) + } + + // Basic Constraints + val pathLengthConstraint: Int = certMaterial.pathLengthConstraint + if (pathLengthConstraint != CertificateMaterial.PATHLENGTH_NOT_A_CA) { + // TODO doesn't work for certificate chains != 2 in size + val basicConstraints = BasicConstraints(pathLengthConstraint) + certBuilder.addExtension(Extension.basicConstraints, CRITICAL, basicConstraints) + } + val extendedKeyUsage: Optional = certMaterial.extendedKeyUsage + if (extendedKeyUsage.isPresent) { + val keyPurpose = KeyPurposeId.getInstance(ASN1ObjectIdentifier(extendedKeyUsage.get())) + val extKeyUsage = ExtendedKeyUsage(arrayOf(keyPurpose)) + certBuilder.addExtension(Extension.extendedKeyUsage, CRITICAL, extKeyUsage) + } + + // DEBUG setProvider(bcProvider) removed before getCertificate + return JcaX509CertificateConverter().getCertificate(certBuilder.build(contentSigner)) + } +} \ No newline at end of file diff --git a/appverifier/src/main/java/com/android/mdl/appreader/readercertgen/CertificateMaterial.java b/appverifier/src/main/java/com/android/mdl/appreader/readercertgen/CertificateMaterial.java deleted file mode 100644 index 79ae8aaf8..000000000 --- a/appverifier/src/main/java/com/android/mdl/appreader/readercertgen/CertificateMaterial.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.android.mdl.appreader.readercertgen; - -import java.math.BigInteger; -import java.util.Date; -import java.util.Optional; - -public interface CertificateMaterial { - int PATHLENGTH_NOT_A_CA = -1; - - BigInteger serialNumber(); - - Date startDate(); - - Date endDate(); - - int keyUsage(); - - Optional extendedKeyUsage(); - - int pathLengthConstraint(); -} \ No newline at end of file diff --git a/appverifier/src/main/java/com/android/mdl/appreader/readercertgen/CertificateMaterial.kt b/appverifier/src/main/java/com/android/mdl/appreader/readercertgen/CertificateMaterial.kt new file mode 100644 index 000000000..870321371 --- /dev/null +++ b/appverifier/src/main/java/com/android/mdl/appreader/readercertgen/CertificateMaterial.kt @@ -0,0 +1,18 @@ +package com.android.mdl.appreader.readercertgen + +import java.math.BigInteger +import java.util.Date +import java.util.Optional + +data class CertificateMaterial( + val serialNumber: BigInteger, + val startDate: Date, + val endDate: Date, + val keyUsage: Int, + val extendedKeyUsage: Optional, + val pathLengthConstraint: Int +) { + companion object { + const val PATHLENGTH_NOT_A_CA = -1 + } +} \ No newline at end of file diff --git a/appverifier/src/main/java/com/android/mdl/appreader/readercertgen/DataMaterial.java b/appverifier/src/main/java/com/android/mdl/appreader/readercertgen/DataMaterial.java deleted file mode 100644 index 79c9358ea..000000000 --- a/appverifier/src/main/java/com/android/mdl/appreader/readercertgen/DataMaterial.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.android.mdl.appreader.readercertgen; - -import java.util.Optional; - -public interface DataMaterial { - String subjectDN(); - - String issuerDN(); - - Optional issuerAlternativeName(); -} - diff --git a/appverifier/src/main/java/com/android/mdl/appreader/readercertgen/DataMaterial.kt b/appverifier/src/main/java/com/android/mdl/appreader/readercertgen/DataMaterial.kt new file mode 100644 index 000000000..a3bbb7e01 --- /dev/null +++ b/appverifier/src/main/java/com/android/mdl/appreader/readercertgen/DataMaterial.kt @@ -0,0 +1,9 @@ +package com.android.mdl.appreader.readercertgen + +import java.util.Optional + +data class DataMaterial( + val subjectDN: String, + val issuerDN: String, + val issuerAlternativeName: Optional +) \ No newline at end of file diff --git a/appverifier/src/main/java/com/android/mdl/appreader/readercertgen/EncodingUtil.java b/appverifier/src/main/java/com/android/mdl/appreader/readercertgen/EncodingUtil.java deleted file mode 100644 index 0fda3cbf9..000000000 --- a/appverifier/src/main/java/com/android/mdl/appreader/readercertgen/EncodingUtil.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.android.mdl.appreader.readercertgen; - -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Locale; - -public final class EncodingUtil { - - private static final SimpleDateFormat SHORT_ISO_DATEFORMAT = new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH); - - private EncodingUtil() { - // TODO Auto-generated constructor stub - } - - static Date parseShortISODate(String date) { - try { - return SHORT_ISO_DATEFORMAT.parse(date); - } catch (ParseException e) { - throw new RuntimeException(e); - } - } - -} diff --git a/appverifier/src/main/java/com/android/mdl/appreader/readercertgen/EncodingUtil.kt b/appverifier/src/main/java/com/android/mdl/appreader/readercertgen/EncodingUtil.kt new file mode 100644 index 000000000..488a8e5b4 --- /dev/null +++ b/appverifier/src/main/java/com/android/mdl/appreader/readercertgen/EncodingUtil.kt @@ -0,0 +1,17 @@ +package com.android.mdl.appreader.readercertgen + +import java.text.ParseException +import java.text.SimpleDateFormat +import java.util.Date +import java.util.Locale + +object EncodingUtil { + private val SHORT_ISO_DATEFORMAT = SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH) + fun parseShortISODate(date: String): Date { + return try { + SHORT_ISO_DATEFORMAT.parse(date)!! + } catch (e: ParseException) { + throw RuntimeException(e) + } + } +} \ No newline at end of file diff --git a/appverifier/src/main/java/com/android/mdl/appreader/readercertgen/KeyMaterial.java b/appverifier/src/main/java/com/android/mdl/appreader/readercertgen/KeyMaterial.java deleted file mode 100644 index ded9b2b73..000000000 --- a/appverifier/src/main/java/com/android/mdl/appreader/readercertgen/KeyMaterial.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.android.mdl.appreader.readercertgen; - -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.cert.X509Certificate; -import java.util.Optional; - -public interface KeyMaterial { - PublicKey publicKey(); - - String signingAlgorithm(); - - Optional issuerCertificate(); - - PrivateKey signingKey(); -} - diff --git a/appverifier/src/main/java/com/android/mdl/appreader/readercertgen/KeyMaterial.kt b/appverifier/src/main/java/com/android/mdl/appreader/readercertgen/KeyMaterial.kt new file mode 100644 index 000000000..f6593ded7 --- /dev/null +++ b/appverifier/src/main/java/com/android/mdl/appreader/readercertgen/KeyMaterial.kt @@ -0,0 +1,13 @@ +package com.android.mdl.appreader.readercertgen + +import java.security.PrivateKey +import java.security.PublicKey +import java.security.cert.X509Certificate +import java.util.Optional + +data class KeyMaterial( + val publicKey: PublicKey, + val signingAlgorithm: String, + val issuerCertificate: Optional, + val signingKey: PrivateKey +) \ No newline at end of file diff --git a/appverifier/src/main/java/com/android/mdl/appreader/readercertgen/ReaderCertificateGenerator.java b/appverifier/src/main/java/com/android/mdl/appreader/readercertgen/ReaderCertificateGenerator.java deleted file mode 100644 index b4aaeef1e..000000000 --- a/appverifier/src/main/java/com/android/mdl/appreader/readercertgen/ReaderCertificateGenerator.java +++ /dev/null @@ -1,139 +0,0 @@ -package com.android.mdl.appreader.readercertgen; - -import org.bouncycastle.asn1.x509.KeyUsage; -import org.bouncycastle.jce.provider.BouncyCastleProvider; - -import java.math.BigInteger; -import java.security.InvalidAlgorithmParameterException; -import java.security.KeyPair; -import java.security.KeyPairGenerator; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.cert.X509Certificate; -import java.security.spec.ECGenParameterSpec; -import java.util.Date; -import java.util.Optional; - -/** - * Generates a key pair for a specific curve, creates a reader certificate around it using - * the given issuing CA certificate and private key to sign it. - *

- * Usage: - * final KeyPair readerKeyPair = generateECDSAKeyPair(curve); - * X509Certificate dsCertificate = createReaderCertificate(readerKeyPair, iacaCertificate, iacaKeyPair.getPrivate()); - */ -public final class ReaderCertificateGenerator { - - private ReaderCertificateGenerator() { - // avoid instantiation - } - - public static KeyPair generateECDSAKeyPair(String curve) { - try { - // NOTE older devices may not have the right BC installed for this to work - KeyPairGenerator kpg; - if (curve.equalsIgnoreCase("Ed25519") || curve.equalsIgnoreCase("Ed448")) { - kpg = KeyPairGenerator.getInstance(curve, new BouncyCastleProvider()); - } else { - kpg = KeyPairGenerator.getInstance("EC", new BouncyCastleProvider()); - kpg.initialize(new ECGenParameterSpec(curve)); - } - System.out.println(kpg.getProvider().getInfo()); - return kpg.generateKeyPair(); - } catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException e) { - throw new RuntimeException(e); - } - } - - public static X509Certificate createReaderCertificate(KeyPair dsKeyPair, X509Certificate issuerCert, - PrivateKey issuerPrivateKey) throws Exception { - DataMaterial data = new DataMaterial() { - - @Override - public String subjectDN() { - return "C=UT, CN=Google mDoc Reader"; - } - - @Override - public String issuerDN() { - // must match DN of issuer character-by-character - // TODO change for other generators - return issuerCert.getSubjectX500Principal().getName(); - - // reorders string, do not use - // return issuerCert.getSubjectX500Principal().getName(); - } - - @Override - public Optional issuerAlternativeName() { - // NOTE always interpreted as URL for now - return Optional.of("https://www.google.com/"); - } - }; - - CertificateMaterial certData = new CertificateMaterial() { - - @Override - public BigInteger serialNumber() { - // TODO change - return new BigInteger("476f6f676c655f546573745f44535f31", 16); - } - - @Override - public Date startDate() { - return EncodingUtil.parseShortISODate("2023-01-01"); - } - - @Override - public Date endDate() { - return EncodingUtil.parseShortISODate("2024-01-01"); - } - - @Override - public int pathLengthConstraint() { - return CertificateMaterial.PATHLENGTH_NOT_A_CA; - } - - @Override - public int keyUsage() { - return KeyUsage.digitalSignature; - } - - @Override - public Optional extendedKeyUsage() { - // TODO change for reader cert - return Optional.of("1.0.18013.5.1.6"); - } - }; - - KeyMaterial keyData = new KeyMaterial() { - - @Override - public PublicKey publicKey() { - return dsKeyPair.getPublic(); - } - - @Override - public String signingAlgorithm() { - return "SHA384WithECDSA"; - } - - @Override - public PrivateKey signingKey() { - return issuerPrivateKey; - } - - @Override - public Optional issuerCertificate() { - return Optional.of(issuerCert); - } - }; - - // C.1.7.2 - - X509Certificate readerCert = CertificateGenerator.generateCertificate(data, certData, keyData); - - return readerCert; - } -} diff --git a/appverifier/src/main/java/com/android/mdl/appreader/readercertgen/ReaderCertificateGenerator.kt b/appverifier/src/main/java/com/android/mdl/appreader/readercertgen/ReaderCertificateGenerator.kt new file mode 100644 index 000000000..8ef7f72f5 --- /dev/null +++ b/appverifier/src/main/java/com/android/mdl/appreader/readercertgen/ReaderCertificateGenerator.kt @@ -0,0 +1,87 @@ +package com.android.mdl.appreader.readercertgen + +import com.android.mdl.appreader.readercertgen.CertificateGenerator.generateCertificate +import org.bouncycastle.asn1.x509.KeyUsage +import org.bouncycastle.jce.provider.BouncyCastleProvider +import java.math.BigInteger +import java.security.InvalidAlgorithmParameterException +import java.security.KeyPair +import java.security.KeyPairGenerator +import java.security.NoSuchAlgorithmException +import java.security.PrivateKey +import java.security.cert.X509Certificate +import java.security.spec.ECGenParameterSpec +import java.util.Optional + +/** + * Generates a key pair for a specific curve, creates a reader certificate around it using + * the given issuing CA certificate and private key to sign it. + * + * + * Usage: + * final KeyPair readerKeyPair = generateECDSAKeyPair(curve); + * X509Certificate dsCertificate = createReaderCertificate(readerKeyPair, iacaCertificate, iacaKeyPair.getPrivate()); + */ +object ReaderCertificateGenerator { + fun generateECDSAKeyPair(curve: String): KeyPair { + return try { + // NOTE older devices may not have the right BC installed for this to work + val kpg: KeyPairGenerator + if (curve.equals("Ed25519", ignoreCase = true) || curve.equals( + "Ed448", + ignoreCase = true + ) + ) { + kpg = KeyPairGenerator.getInstance(curve, BouncyCastleProvider()) + } else { + kpg = KeyPairGenerator.getInstance("EC", BouncyCastleProvider()) + kpg.initialize(ECGenParameterSpec(curve)) + } + println(kpg.provider.info) + kpg.generateKeyPair() + } catch (e: NoSuchAlgorithmException) { + throw RuntimeException(e) + } catch (e: InvalidAlgorithmParameterException) { + throw RuntimeException(e) + } + } + + @Throws(Exception::class) + fun createReaderCertificate( + dsKeyPair: KeyPair, issuerCert: X509Certificate, + issuerPrivateKey: PrivateKey + ): X509Certificate { + val data = DataMaterial( + subjectDN = "C=UT, CN=Google mDoc Reader", + + // must match DN of issuer character-by-character + // TODO change for other generators + issuerDN = issuerCert.subjectX500Principal.name, + // reorders string, do not use + // return issuerCert.getSubjectX500Principal().getName(); + + // NOTE always interpreted as URL for now + issuerAlternativeName = Optional.of("https://www.google.com/") + ) + val certData = CertificateMaterial( + // TODO change + serialNumber = BigInteger("476f6f676c655f546573745f44535f31", 16), + startDate = EncodingUtil.parseShortISODate("2023-01-01"), + endDate = EncodingUtil.parseShortISODate("2024-01-01"), + pathLengthConstraint = CertificateMaterial.PATHLENGTH_NOT_A_CA, + keyUsage = KeyUsage.digitalSignature, + // TODO change for reader cert + extendedKeyUsage = Optional.of("1.0.18013.5.1.6") + ) + + val keyData = KeyMaterial( + publicKey = dsKeyPair.public, + signingAlgorithm = "SHA384WithECDSA", + signingKey = issuerPrivateKey, + issuerCertificate = Optional.of(issuerCert) + ) + + // C.1.7.2 + return generateCertificate(data, certData, keyData) + } +} \ No newline at end of file diff --git a/appverifier/src/main/java/com/android/mdl/appreader/readercertgen/SupportedCurves.java b/appverifier/src/main/java/com/android/mdl/appreader/readercertgen/SupportedCurves.kt similarity index 61% rename from appverifier/src/main/java/com/android/mdl/appreader/readercertgen/SupportedCurves.java rename to appverifier/src/main/java/com/android/mdl/appreader/readercertgen/SupportedCurves.kt index 8350a81fe..24a062282 100644 --- a/appverifier/src/main/java/com/android/mdl/appreader/readercertgen/SupportedCurves.java +++ b/appverifier/src/main/java/com/android/mdl/appreader/readercertgen/SupportedCurves.kt @@ -1,6 +1,6 @@ -package com.android.mdl.appreader.readercertgen; +package com.android.mdl.appreader.readercertgen -public enum SupportedCurves { +enum class SupportedCurves { SECP256R1, SECP384R1, SECP521R1, @@ -9,4 +9,4 @@ public enum SupportedCurves { BRAINPOOLP512R1, ED25519, ED448 -} +} \ No newline at end of file From 147fadd3c4a0e811a9358f1d4c83dbe86e86684a Mon Sep 17 00:00:00 2001 From: Kees Geluk Date: Mon, 30 Oct 2023 14:10:00 +0100 Subject: [PATCH 2/2] Changes after feedback from Jovche --- .../mdl/appreader/readercertgen/CertificateGenerator.kt | 8 +------- .../appreader/readercertgen/ReaderCertificateGenerator.kt | 7 +------ 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/appverifier/src/main/java/com/android/mdl/appreader/readercertgen/CertificateGenerator.kt b/appverifier/src/main/java/com/android/mdl/appreader/readercertgen/CertificateGenerator.kt index 0eece90e4..fc9efe1d1 100644 --- a/appverifier/src/main/java/com/android/mdl/appreader/readercertgen/CertificateGenerator.kt +++ b/appverifier/src/main/java/com/android/mdl/appreader/readercertgen/CertificateGenerator.kt @@ -17,7 +17,6 @@ import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder import org.bouncycastle.operator.OperatorCreationException import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder import java.io.IOException -import java.security.NoSuchAlgorithmException import java.security.cert.CertificateException import java.security.cert.X509Certificate import java.util.Optional @@ -49,12 +48,7 @@ object CertificateGenerator { // Extensions -------------------------- - val jcaX509ExtensionUtils: JcaX509ExtensionUtils - jcaX509ExtensionUtils = try { - JcaX509ExtensionUtils() - } catch (e: NoSuchAlgorithmException) { - throw RuntimeException(e) - } + val jcaX509ExtensionUtils = JcaX509ExtensionUtils() if (issuerCert.isPresent) { try { // adds 3 more fields, not present in other cert diff --git a/appverifier/src/main/java/com/android/mdl/appreader/readercertgen/ReaderCertificateGenerator.kt b/appverifier/src/main/java/com/android/mdl/appreader/readercertgen/ReaderCertificateGenerator.kt index 8ef7f72f5..4e7632856 100644 --- a/appverifier/src/main/java/com/android/mdl/appreader/readercertgen/ReaderCertificateGenerator.kt +++ b/appverifier/src/main/java/com/android/mdl/appreader/readercertgen/ReaderCertificateGenerator.kt @@ -27,11 +27,7 @@ object ReaderCertificateGenerator { return try { // NOTE older devices may not have the right BC installed for this to work val kpg: KeyPairGenerator - if (curve.equals("Ed25519", ignoreCase = true) || curve.equals( - "Ed448", - ignoreCase = true - ) - ) { + if (listOf("Ed25519", "Ed448").any { it.equals(curve, ignoreCase = true) }) { kpg = KeyPairGenerator.getInstance(curve, BouncyCastleProvider()) } else { kpg = KeyPairGenerator.getInstance("EC", BouncyCastleProvider()) @@ -46,7 +42,6 @@ object ReaderCertificateGenerator { } } - @Throws(Exception::class) fun createReaderCertificate( dsKeyPair: KeyPair, issuerCert: X509Certificate, issuerPrivateKey: PrivateKey