1 /*
2  * Copyright (C) 2021 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.remoteprovisioner.unittest;
18 
19 import com.google.crypto.tink.subtle.Ed25519Sign;
20 
21 import co.nstant.in.cbor.CborBuilder;
22 import co.nstant.in.cbor.CborEncoder;
23 import co.nstant.in.cbor.model.Array;
24 
25 import org.bouncycastle.asn1.x509.BasicConstraints;
26 import org.bouncycastle.asn1.x509.Extension;
27 import org.bouncycastle.asn1.x509.KeyUsage;
28 import org.bouncycastle.x509.X509V3CertificateGenerator;
29 
30 import java.io.ByteArrayOutputStream;
31 import java.math.BigInteger;
32 import java.security.AlgorithmParameters;
33 import java.security.KeyFactory;
34 import java.security.KeyPair;
35 import java.security.KeyPairGenerator;
36 import java.security.MessageDigest;
37 import java.security.PublicKey;
38 import java.security.cert.X509Certificate;
39 import java.security.spec.ECGenParameterSpec;
40 import java.security.spec.ECParameterSpec;
41 import java.security.spec.ECPoint;
42 import java.security.spec.ECPublicKeySpec;
43 import java.time.Duration;
44 import java.time.Instant;
45 import java.util.Date;
46 
47 import javax.security.auth.x500.X500Principal;
48 
49 /**
50  * Utility class for unit testing.
51  */
52 public class Utils {
53     private static final int KEY_TYPE = 1;
54     private static final int KEY_TYPE_OKP = 1;
55     private static final int KID = 2;
56     private static final int ALGORITHM = 3;
57     private static final int ALGORITHM_EDDSA = -8;
58     private static final int ALGORITHM_ECDH_ES_HKDF_256 = -25;
59     private static final int CURVE = -1;
60     private static final int CURVE_X25519 = 4;
61     private static final int CURVE_ED25519 = 6;
62     private static final int X_COORDINATE = -2;
63 
getP256PubKeyFromBytes(byte[] xPub, byte[] yPub)64     public static PublicKey getP256PubKeyFromBytes(byte[] xPub, byte[] yPub) throws Exception {
65         BigInteger x = new BigInteger(1, xPub);
66         BigInteger y = new BigInteger(1, yPub);
67         AlgorithmParameters parameters = AlgorithmParameters.getInstance("EC");
68         parameters.init(new ECGenParameterSpec("secp256r1"));
69         ECParameterSpec ecParameters = parameters.getParameterSpec(ECParameterSpec.class);
70         ECPoint point = new ECPoint(x, y);
71         ECPublicKeySpec keySpec = new ECPublicKeySpec(point, ecParameters);
72         KeyFactory keyFactory = KeyFactory.getInstance("EC");
73         return keyFactory.generatePublic(keySpec);
74     }
75 
generateEcdsaKeyPair()76     public static KeyPair generateEcdsaKeyPair() throws Exception {
77         KeyPairGenerator generator = KeyPairGenerator.getInstance("EC");
78         ECGenParameterSpec params = new ECGenParameterSpec("secp256r1");
79         generator.initialize(params);
80         return generator.generateKeyPair();
81     }
82 
signPublicKey(KeyPair issuerKeyPair, PublicKey publicKeyToSign)83     public static X509Certificate signPublicKey(KeyPair issuerKeyPair, PublicKey publicKeyToSign)
84             throws Exception {
85         X500Principal issuer = new X500Principal("CN=TEE");
86         BigInteger serial = BigInteger.ONE;
87         X500Principal subject = new X500Principal("CN=TEE");
88 
89         Instant now = Instant.now();
90         X509V3CertificateGenerator certificateBuilder = new X509V3CertificateGenerator();
91         certificateBuilder.setIssuerDN(issuer);
92         certificateBuilder.setSerialNumber(serial);
93         certificateBuilder.setNotBefore(Date.from(now));
94         certificateBuilder.setNotAfter(Date.from(now.plus(Duration.ofDays(1))));
95         certificateBuilder.setSignatureAlgorithm("SHA256WITHECDSA");
96         certificateBuilder.setSubjectDN(subject);
97         certificateBuilder.setPublicKey(publicKeyToSign);
98         certificateBuilder.addExtension(
99                 Extension.basicConstraints, /*isCritical=*/ true, new BasicConstraints(true));
100         certificateBuilder.addExtension(
101                 Extension.keyUsage, /*isCritical=*/ true, new KeyUsage(KeyUsage.keyCertSign));
102         return certificateBuilder.generate(issuerKeyPair.getPrivate());
103     }
104 
encodeAndSignSign1Ed25519(byte[] encodedPublicKey, byte[] privateKey)105     public static Array encodeAndSignSign1Ed25519(byte[] encodedPublicKey, byte[] privateKey)
106             throws Exception {
107         byte[] encodedProtectedHeaders = encodeSimpleMap(1, -8);
108         return (Array) (new CborBuilder()
109             .addArray()
110                 .add(encodedProtectedHeaders)      // Protected headers
111                 .addMap()                          // Empty unprotected Headers
112                     .end()
113                 .add(encodedPublicKey)
114                 .add(encodeAndSignSigStructure(
115                         encodedProtectedHeaders, encodedPublicKey, privateKey))
116             .end()
117             .build().get(0));
118     }
119 
encodeAndSignSigStructure( byte[] protectedHeaders, byte[] payload, byte[] privateKey)120     private static byte[] encodeAndSignSigStructure(
121             byte[] protectedHeaders, byte[] payload, byte[] privateKey) throws Exception {
122         return encodeAndSignSigStructure(protectedHeaders, null, payload, privateKey);
123     }
124 
encodeAndSignSigStructure(byte[] protectedHeaders, byte[] externalAad, byte[] payload, byte[] privateKey)125     private static byte[] encodeAndSignSigStructure(byte[] protectedHeaders, byte[] externalAad,
126                                                     byte[] payload, byte[] privateKey)
127             throws Exception {
128         ByteArrayOutputStream baos = new ByteArrayOutputStream();
129         new CborEncoder(baos).encode(new CborBuilder()
130                 .addArray()
131                     .add("Signature1")                                      // context string
132                     .add(protectedHeaders)                                  // protected headers
133                     .add(null == externalAad ? new byte[0] : externalAad)   // external aad
134                     .add(payload)                                           // payload
135                     .end()
136                 .build());
137         Ed25519Sign signer = new Ed25519Sign(privateKey);
138         return signer.sign(baos.toByteArray());
139     }
140 
encodeEd25519PubKey(byte[] publicKey)141     public static byte[] encodeEd25519PubKey(byte[] publicKey) throws Exception {
142         ByteArrayOutputStream baos = new ByteArrayOutputStream();
143         new CborEncoder(baos).encode(new CborBuilder()
144                 .addMap()
145                     .put(KEY_TYPE, KEY_TYPE_OKP)
146                     .put(ALGORITHM, ALGORITHM_EDDSA)
147                     .put(CURVE, CURVE_ED25519)
148                     .put(X_COORDINATE, publicKey)
149                     .end()
150                 .build());
151         return baos.toByteArray();
152     }
153 
encodeX25519PubKey(byte[] publicKey)154     public static byte[] encodeX25519PubKey(byte[] publicKey) throws Exception {
155         ByteArrayOutputStream baos = new ByteArrayOutputStream();
156         MessageDigest digest = MessageDigest.getInstance("SHA-256");
157         byte[] kid = digest.digest(publicKey);
158         new CborEncoder(baos).encode(new CborBuilder()
159                 .addMap()
160                     .put(KEY_TYPE, KEY_TYPE_OKP)
161                     .put(KID, kid)
162                     .put(ALGORITHM, ALGORITHM_ECDH_ES_HKDF_256)
163                     .put(CURVE, CURVE_X25519)
164                     .put(X_COORDINATE, publicKey)
165                     .end()
166                 .build());
167         return baos.toByteArray();
168     }
169 
encodeSimpleMap(int key, int value)170     private static byte[] encodeSimpleMap(int key, int value) throws Exception {
171         ByteArrayOutputStream baos = new ByteArrayOutputStream();
172         new CborEncoder(baos).encode(new CborBuilder()
173                 .addMap()
174                     .put(key, value)
175                     .end()
176                 .build());
177         return baos.toByteArray();
178     }
179 }
180