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.keystore.cts;
18 
19 import com.google.common.collect.ImmutableSet;
20 
21 import com.android.org.bouncycastle.asn1.ASN1Boolean;
22 import com.android.org.bouncycastle.asn1.ASN1Encodable;
23 import com.android.org.bouncycastle.asn1.ASN1Enumerated;
24 import com.android.org.bouncycastle.asn1.ASN1InputStream;
25 import com.android.org.bouncycastle.asn1.ASN1Integer;
26 import com.android.org.bouncycastle.asn1.ASN1OctetString;
27 import com.android.org.bouncycastle.asn1.ASN1Primitive;
28 import com.android.org.bouncycastle.asn1.ASN1Sequence;
29 import com.android.org.bouncycastle.asn1.ASN1Set;
30 import com.android.org.bouncycastle.asn1.DEROctetString;
31 
32 import java.io.IOException;
33 import java.math.BigInteger;
34 import java.security.cert.CertificateParsingException;
35 import java.util.Date;
36 import java.util.Enumeration;
37 import java.util.Set;
38 
39 public class Asn1Utils {
40 
getIntegerFromAsn1(ASN1Encodable asn1Value)41     public static int getIntegerFromAsn1(ASN1Encodable asn1Value)
42             throws CertificateParsingException {
43         if (asn1Value instanceof ASN1Integer) {
44             return bigIntegerToInt(((ASN1Integer) asn1Value).getValue());
45         } else if (asn1Value instanceof ASN1Enumerated) {
46             return bigIntegerToInt(((ASN1Enumerated) asn1Value).getValue());
47         } else {
48             throw new CertificateParsingException(
49                     "Integer value expected, " + asn1Value.getClass().getName() + " found.");
50         }
51     }
52 
getLongFromAsn1(ASN1Encodable asn1Value)53     public static Long getLongFromAsn1(ASN1Encodable asn1Value) throws CertificateParsingException {
54         if (asn1Value instanceof ASN1Integer) {
55             return bigIntegerToLong(((ASN1Integer) asn1Value).getValue());
56         } else {
57             throw new CertificateParsingException(
58                     "Integer value expected, " + asn1Value.getClass().getName() + " found.");
59         }
60     }
61 
getByteArrayFromAsn1(ASN1Encodable asn1Encodable)62     public static byte[] getByteArrayFromAsn1(ASN1Encodable asn1Encodable)
63             throws CertificateParsingException {
64         if (asn1Encodable == null || !(asn1Encodable instanceof DEROctetString)) {
65             throw new CertificateParsingException("Expected DEROctetString");
66         }
67         ASN1OctetString derOctectString = (ASN1OctetString) asn1Encodable;
68         return derOctectString.getOctets();
69     }
70 
getAsn1SequenceFromBytes(byte[] bytes)71     public static ASN1Sequence getAsn1SequenceFromBytes(byte[] bytes)
72             throws CertificateParsingException {
73         try (ASN1InputStream asn1InputStream = new ASN1InputStream(bytes)) {
74             return getAsn1SequenceFromStream(asn1InputStream);
75         } catch (IOException e) {
76             throw new CertificateParsingException("Failed to parse SEQUENCE", e);
77         }
78     }
79 
getAsn1SequenceFromStream(final ASN1InputStream asn1InputStream)80     public static ASN1Sequence getAsn1SequenceFromStream(final ASN1InputStream asn1InputStream)
81             throws IOException, CertificateParsingException {
82         ASN1Primitive asn1Primitive = asn1InputStream.readObject();
83         if (!(asn1Primitive instanceof ASN1OctetString)) {
84             throw new CertificateParsingException(
85                     "Expected octet stream, found " + asn1Primitive.getClass().getName());
86         }
87         try (ASN1InputStream seqInputStream = new ASN1InputStream(
88                 ((ASN1OctetString) asn1Primitive).getOctets())) {
89             asn1Primitive = seqInputStream.readObject();
90             if (!(asn1Primitive instanceof ASN1Sequence)) {
91                 throw new CertificateParsingException(
92                         "Expected sequence, found " + asn1Primitive.getClass().getName());
93             }
94             return (ASN1Sequence) asn1Primitive;
95         }
96     }
97 
getIntegersFromAsn1Set(ASN1Encodable set)98     public static Set<Integer> getIntegersFromAsn1Set(ASN1Encodable set)
99             throws CertificateParsingException {
100         if (!(set instanceof ASN1Set)) {
101             throw new CertificateParsingException(
102                     "Expected set, found " + set.getClass().getName());
103         }
104 
105         ImmutableSet.Builder<Integer> builder = ImmutableSet.builder();
106         for (Enumeration<?> e = ((ASN1Set) set).getObjects(); e.hasMoreElements();) {
107             builder.add(getIntegerFromAsn1((ASN1Integer) e.nextElement()));
108         }
109         return builder.build();
110     }
111 
getDateFromAsn1(ASN1Primitive value)112     public static Date getDateFromAsn1(ASN1Primitive value) throws CertificateParsingException {
113         return new Date(getLongFromAsn1(value));
114     }
115 
getBooleanFromAsn1(ASN1Encodable value)116     public static boolean getBooleanFromAsn1(ASN1Encodable value)
117             throws CertificateParsingException {
118         if (!(value instanceof ASN1Boolean)) {
119             throw new CertificateParsingException(
120                     "Expected boolean, found " + value.getClass().getName());
121         }
122         return ((ASN1Boolean) value).isTrue();
123     }
124 
bigIntegerToInt(BigInteger bigInt)125     private static int bigIntegerToInt(BigInteger bigInt) throws CertificateParsingException {
126         if (bigInt.compareTo(BigInteger.valueOf(Integer.MAX_VALUE)) > 0
127                 || bigInt.compareTo(BigInteger.ZERO) < 0) {
128             throw new CertificateParsingException("INTEGER out of bounds");
129         }
130         return bigInt.intValue();
131     }
132 
bigIntegerToLong(BigInteger bigInt)133     private static long bigIntegerToLong(BigInteger bigInt) throws CertificateParsingException {
134         if (bigInt.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) > 0
135                 || bigInt.compareTo(BigInteger.ZERO) < 0) {
136             throw new CertificateParsingException("INTEGER out of bounds");
137         }
138         return bigInt.longValue();
139     }
140 }
141