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