1/*
2 * Copyright (C) 2013 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
17package org.conscrypt;
18
19import java.io.ByteArrayOutputStream;
20import java.math.BigInteger;
21import java.security.cert.CRLException;
22import java.security.cert.X509CRLEntry;
23import java.util.Arrays;
24import java.util.Calendar;
25import java.util.Date;
26import java.util.HashSet;
27import java.util.Set;
28import java.util.TimeZone;
29
30public class OpenSSLX509CRLEntry extends X509CRLEntry {
31    private final long mContext;
32
33    OpenSSLX509CRLEntry(long ctx) {
34        mContext = ctx;
35    }
36
37    @Override
38    public Set<String> getCriticalExtensionOIDs() {
39        String[] critOids =
40                NativeCrypto.get_X509_REVOKED_ext_oids(mContext,
41                        NativeCrypto.EXTENSION_TYPE_CRITICAL);
42
43        /*
44         * This API has a special case that if there are no extensions, we
45         * should return null. So if we have no critical extensions, we'll check
46         * non-critical extensions.
47         */
48        if ((critOids.length == 0)
49                && (NativeCrypto.get_X509_REVOKED_ext_oids(mContext,
50                        NativeCrypto.EXTENSION_TYPE_NON_CRITICAL).length == 0)) {
51            return null;
52        }
53
54        return new HashSet<String>(Arrays.asList(critOids));
55    }
56
57    @Override
58    public byte[] getExtensionValue(String oid) {
59        return NativeCrypto.X509_REVOKED_get_ext_oid(mContext, oid);
60    }
61
62    @Override
63    public Set<String> getNonCriticalExtensionOIDs() {
64        String[] critOids =
65                NativeCrypto.get_X509_REVOKED_ext_oids(mContext,
66                        NativeCrypto.EXTENSION_TYPE_NON_CRITICAL);
67
68        /*
69         * This API has a special case that if there are no extensions, we
70         * should return null. So if we have no non-critical extensions, we'll
71         * check critical extensions.
72         */
73        if ((critOids.length == 0)
74                && (NativeCrypto.get_X509_REVOKED_ext_oids(mContext,
75                        NativeCrypto.EXTENSION_TYPE_CRITICAL).length == 0)) {
76            return null;
77        }
78
79        return new HashSet<String>(Arrays.asList(critOids));
80    }
81
82    @Override
83    public boolean hasUnsupportedCriticalExtension() {
84        final String[] criticalOids =
85                NativeCrypto.get_X509_REVOKED_ext_oids(mContext,
86                        NativeCrypto.EXTENSION_TYPE_CRITICAL);
87        for (String oid : criticalOids) {
88            final long extensionRef = NativeCrypto.X509_REVOKED_get_ext(mContext, oid);
89            if (NativeCrypto.X509_supported_extension(extensionRef) != 1) {
90                return true;
91            }
92        }
93
94        return false;
95    }
96
97    @Override
98    public byte[] getEncoded() throws CRLException {
99        return NativeCrypto.i2d_X509_REVOKED(mContext);
100    }
101
102    @Override
103    public BigInteger getSerialNumber() {
104        return new BigInteger(NativeCrypto.X509_REVOKED_get_serialNumber(mContext));
105    }
106
107    @Override
108    public Date getRevocationDate() {
109        Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
110        calendar.set(Calendar.MILLISECOND, 0);
111        NativeCrypto.ASN1_TIME_to_Calendar(NativeCrypto.get_X509_REVOKED_revocationDate(mContext),
112                calendar);
113        return calendar.getTime();
114    }
115
116    @Override
117    public boolean hasExtensions() {
118        return (NativeCrypto.get_X509_REVOKED_ext_oids(mContext,
119                NativeCrypto.EXTENSION_TYPE_NON_CRITICAL).length != 0)
120                || (NativeCrypto.get_X509_REVOKED_ext_oids(mContext,
121                        NativeCrypto.EXTENSION_TYPE_CRITICAL).length != 0);
122    }
123
124    @Override
125    public String toString() {
126        ByteArrayOutputStream os = new ByteArrayOutputStream();
127        long bioCtx = NativeCrypto.create_BIO_OutputStream(os);
128        try {
129            NativeCrypto.X509_REVOKED_print(bioCtx, mContext);
130            return os.toString();
131        } finally {
132            NativeCrypto.BIO_free_all(bioCtx);
133        }
134    }
135}
136