1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.tools.build.apkzlib.sign; 18 19 import static org.junit.Assert.assertNotNull; 20 import static org.junit.Assert.fail; 21 22 import com.android.tools.build.apkzlib.utils.ApkZLibPair; 23 import java.math.BigInteger; 24 import java.security.KeyPair; 25 import java.security.KeyPairGenerator; 26 import java.security.NoSuchAlgorithmException; 27 import java.security.PrivateKey; 28 import java.security.cert.X509Certificate; 29 import java.security.interfaces.ECPublicKey; 30 import java.security.interfaces.RSAPublicKey; 31 import java.util.Date; 32 import javax.annotation.Nonnull; 33 import javax.security.auth.x500.X500Principal; 34 import org.bouncycastle.asn1.x500.X500Name; 35 import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; 36 import org.bouncycastle.cert.X509CertificateHolder; 37 import org.bouncycastle.cert.X509v1CertificateBuilder; 38 import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; 39 import org.bouncycastle.crypto.params.RSAKeyParameters; 40 import org.bouncycastle.crypto.util.SubjectPublicKeyInfoFactory; 41 import org.bouncycastle.jce.provider.BouncyCastleProvider; 42 import org.bouncycastle.operator.ContentSigner; 43 import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; 44 import org.junit.Assume; 45 46 /** 47 * Utilities to use signatures in tests. 48 */ 49 public class SignatureTestUtils { 50 51 /** 52 * Generates a private key / certificate for pre-18 systems. 53 * 54 * @return the pair with the private key and certificate 55 * @throws Exception failed to generate the signature data 56 */ 57 @Nonnull generateSignaturePre18()58 public static ApkZLibPair<PrivateKey, X509Certificate> generateSignaturePre18() 59 throws Exception { 60 return generateSignature("RSA", "SHA1withRSA"); 61 } 62 63 /** 64 * Generates a private key / certificate for post-18 systems. 65 * 66 * @return the pair with the private key and certificate 67 * @throws Exception failed to generate the signature data 68 */ 69 @Nonnull generateSignaturePos18()70 public static ApkZLibPair<PrivateKey, X509Certificate> generateSignaturePos18() 71 throws Exception { 72 return generateSignature("EC", "SHA256withECDSA"); 73 } 74 75 /** 76 * Generates a private key / certificate. 77 * 78 * @param sign the asymmetric cypher, <em>e.g.</em>, {@code RSA} 79 * @param full the full signature algorithm name, <em>e.g.</em>, {@code SHA1withRSA} 80 * @return the pair with the private key and certificate 81 * @throws Exception failed to generate the signature data 82 */ 83 @Nonnull generateSignature( @onnull String sign, @Nonnull String full)84 public static ApkZLibPair<PrivateKey, X509Certificate> generateSignature( 85 @Nonnull String sign, 86 @Nonnull String full) 87 throws Exception { 88 // http://stackoverflow.com/questions/28538785/ 89 // easy-way-to-generate-a-self-signed-certificate-for-java-security-keystore-using 90 91 KeyPairGenerator generator = null; 92 try { 93 generator = KeyPairGenerator.getInstance(sign); 94 } catch (NoSuchAlgorithmException e) { 95 Assume.assumeNoException("Algorithm " + sign + " not supported.", e); 96 } 97 98 assertNotNull(generator); 99 KeyPair keyPair = generator.generateKeyPair(); 100 101 Date notBefore = new Date(System.currentTimeMillis() - 24 * 60 * 60 * 1000); 102 Date notAfter = new Date(System.currentTimeMillis() + 365L * 24 * 60 * 60 * 1000); 103 104 X500Name issuer = new X500Name(new X500Principal("cn=Myself").getName()); 105 106 SubjectPublicKeyInfo publicKeyInfo; 107 108 if (keyPair.getPublic() instanceof RSAPublicKey) { 109 RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic(); 110 publicKeyInfo = SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo( 111 new RSAKeyParameters(false, rsaPublicKey.getModulus(), 112 rsaPublicKey.getPublicExponent())); 113 } else if (keyPair.getPublic() instanceof ECPublicKey) { 114 publicKeyInfo = SubjectPublicKeyInfo.getInstance(keyPair.getPublic().getEncoded()); 115 } else { 116 fail(); 117 publicKeyInfo = null; 118 } 119 120 X509v1CertificateBuilder builder = new X509v1CertificateBuilder(issuer, BigInteger.ONE, 121 notBefore, notAfter, issuer, publicKeyInfo); 122 123 ContentSigner signer = new JcaContentSignerBuilder(full).setProvider( 124 new BouncyCastleProvider()).build(keyPair.getPrivate()); 125 X509CertificateHolder holder = builder.build(signer); 126 127 JcaX509CertificateConverter converter = new JcaX509CertificateConverter() 128 .setProvider(new BouncyCastleProvider()); 129 130 return new ApkZLibPair(keyPair.getPrivate(), converter.getCertificate(holder)); 131 } 132 133 } 134