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 android.net.wifi; 18 19 import android.os.Parcel; 20 21 import java.io.ByteArrayInputStream; 22 import java.security.KeyFactory; 23 import java.security.NoSuchAlgorithmException; 24 import java.security.PrivateKey; 25 import java.security.cert.CertificateEncodingException; 26 import java.security.cert.CertificateException; 27 import java.security.cert.CertificateFactory; 28 import java.security.cert.X509Certificate; 29 import java.security.spec.InvalidKeySpecException; 30 import java.security.spec.PKCS8EncodedKeySpec; 31 32 /** 33 * Provides utilities for writing/reading a non-Parcelable objects to/from 34 * a Parcel object. 35 * 36 * @hide 37 */ 38 public class ParcelUtil { 39 /** 40 * Write a PrivateKey object |key| to the specified Parcel |dest|. 41 * 42 * Below is the data format: 43 * |algorithm| -> String of algorithm name 44 * |endcodedKey| -> byte[] of key data 45 * 46 * For a null PrivateKey object, a null string will be written to |algorithm| and 47 * |encodedKey| will be skipped. Since a PrivateKey can only be constructed with 48 * a valid algorithm String. 49 * 50 * @param dest Parcel object to write to 51 * @param key PrivateKey object to read from. 52 */ writePrivateKey(Parcel dest, PrivateKey key)53 public static void writePrivateKey(Parcel dest, PrivateKey key) { 54 if (key == null) { 55 dest.writeString(null); 56 return; 57 } 58 59 dest.writeString(key.getAlgorithm()); 60 dest.writeByteArray(key.getEncoded()); 61 } 62 63 /** 64 * Read/create a PrivateKey object from a specified Parcel object |in|. 65 * 66 * Refer to the function above for the expected data format. 67 * 68 * @param in Parcel object to read from 69 * @return a PrivateKey object or null 70 */ readPrivateKey(Parcel in)71 public static PrivateKey readPrivateKey(Parcel in) { 72 String algorithm = in.readString(); 73 if (algorithm == null) { 74 return null; 75 } 76 77 byte[] userKeyBytes = in.createByteArray(); 78 try { 79 KeyFactory keyFactory = KeyFactory.getInstance(algorithm); 80 return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(userKeyBytes)); 81 } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { 82 return null; 83 } 84 } 85 86 /** 87 * Write a X509Certificate object |cert| to a Parcel object |dest|. 88 * The data being written to the Parcel is just a byte[] of the encoded certificate data. 89 * 90 * @param dest Parcel object to write to 91 * @param cert X509Certificate object to read from 92 */ writeCertificate(Parcel dest, X509Certificate cert)93 public static void writeCertificate(Parcel dest, X509Certificate cert) { 94 byte[] certBytes = null; 95 if (cert != null) { 96 try { 97 certBytes = cert.getEncoded(); 98 } catch (CertificateEncodingException e) { 99 /* empty, write null. */ 100 } 101 } 102 dest.writeByteArray(certBytes); 103 } 104 105 /** 106 * Read/create a X509Certificate object from a specified Parcel object |in|. 107 * 108 * @param in Parcel object to read from 109 * @return a X509Certficate object or null 110 */ readCertificate(Parcel in)111 public static X509Certificate readCertificate(Parcel in) { 112 byte[] certBytes = in.createByteArray(); 113 if (certBytes == null) { 114 return null; 115 } 116 117 try { 118 CertificateFactory cFactory = CertificateFactory.getInstance("X.509"); 119 return (X509Certificate) cFactory 120 .generateCertificate(new ByteArrayInputStream(certBytes)); 121 } catch (CertificateException e) { 122 return null; 123 } 124 } 125 126 /** 127 * Write an array of X509Certificate objects |certs| to a Parcel object |dest|. 128 * The data being written to the Parcel are consist of an integer indicating 129 * the size of the array and the certificates data. Certificates data will be 130 * skipped for a null array or size of 0 array. 131 * 132 * @param dest Parcel object to write to 133 * @param certs array of X509Certificate objects to read from 134 */ writeCertificates(Parcel dest, X509Certificate[] certs)135 public static void writeCertificates(Parcel dest, X509Certificate[] certs) { 136 if (certs == null || certs.length == 0) { 137 dest.writeInt(0); 138 return; 139 } 140 141 dest.writeInt(certs.length); 142 for (int i = 0; i < certs.length; i++) { 143 writeCertificate(dest, certs[i]); 144 } 145 } 146 147 /** 148 * Read/create an array of X509Certificate objects from a specified Parcel object |in|. 149 * 150 * @param in Parcel object to read from 151 * @return X509Certficate[] or null 152 */ readCertificates(Parcel in)153 public static X509Certificate[] readCertificates(Parcel in) { 154 int length = in.readInt(); 155 if (length == 0) { 156 return null; 157 } 158 159 X509Certificate[] certs = new X509Certificate[length]; 160 for (int i = 0; i < length; i++) { 161 certs[i] = readCertificate(in); 162 } 163 return certs; 164 } 165 } 166