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