Home | History | Annotate | Download | only in sign
      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
     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
     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
     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