org.conscrypt.OpenSSLX509CertificateFactory Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of qetcher-client-bundle Show documentation
Show all versions of qetcher-client-bundle Show documentation
Qetcher Java client, OSGi bundle, minimal dependencies
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.conscrypt;
import java.io.IOException;
import java.io.InputStream;
import java.io.PushbackInputStream;
import java.security.cert.CRL;
import java.security.cert.CRLException;
import java.security.cert.CertPath;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactorySpi;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
/**
* An implementation of {@link java.security.cert.CertificateFactory} based on BoringSSL.
*
* @hide
*/
@Internal
public class OpenSSLX509CertificateFactory extends CertificateFactorySpi {
private static final byte[] PKCS7_MARKER = new byte[] {
'-', '-', '-', '-', '-', 'B', 'E', 'G', 'I', 'N', ' ', 'P', 'K', 'C', 'S', '7'
};
private static final int PUSHBACK_SIZE = 64;
static class ParsingException extends Exception {
private static final long serialVersionUID = 8390802697728301325L;
ParsingException(String message) {
super(message);
}
ParsingException(Exception cause) {
super(cause);
}
ParsingException(String message, Exception cause) {
super(message, cause);
}
}
/**
* The code for X509 Certificates and CRL is pretty much the same. We use
* this abstract class to share the code between them. This makes it ugly,
* but it's already written in this language anyway.
*/
private static abstract class Parser {
T generateItem(InputStream inStream) throws ParsingException {
if (inStream == null) {
throw new ParsingException("inStream == null");
}
final boolean markable = inStream.markSupported();
if (markable) {
inStream.mark(PKCS7_MARKER.length);
}
final PushbackInputStream pbis = new PushbackInputStream(inStream, PUSHBACK_SIZE);
try {
final byte[] buffer = new byte[PKCS7_MARKER.length];
final int len = pbis.read(buffer);
if (len < 0) {
/* No need to reset here. The stream was empty or EOF. */
throw new ParsingException("inStream is empty");
}
pbis.unread(buffer, 0, len);
if (buffer[0] == '-') {
if (len == PKCS7_MARKER.length && Arrays.equals(PKCS7_MARKER, buffer)) {
List extends T> items = fromPkcs7PemInputStream(pbis);
if (items.size() == 0) {
return null;
}
items.get(0);
} else {
return fromX509PemInputStream(pbis);
}
}
/* PKCS#7 bags have a byte 0x06 at position 4 in the stream. */
if (buffer[4] == 0x06) {
List extends T> certs = fromPkcs7DerInputStream(pbis);
if (certs.size() == 0) {
return null;
}
return certs.get(0);
} else {
return fromX509DerInputStream(pbis);
}
} catch (Exception e) {
if (markable) {
try {
inStream.reset();
} catch (IOException ignored) {
}
}
throw new ParsingException(e);
}
}
Collection extends T> generateItems(InputStream inStream)
throws ParsingException {
if (inStream == null) {
throw new ParsingException("inStream == null");
}
try {
if (inStream.available() == 0) {
return Collections.emptyList();
}
} catch (IOException e) {
throw new ParsingException("Problem reading input stream", e);
}
final boolean markable = inStream.markSupported();
if (markable) {
inStream.mark(PUSHBACK_SIZE);
}
/* Attempt to see if this is a PKCS#7 bag. */
final PushbackInputStream pbis = new PushbackInputStream(inStream, PUSHBACK_SIZE);
try {
final byte[] buffer = new byte[PKCS7_MARKER.length];
final int len = pbis.read(buffer);
if (len < 0) {
/* No need to reset here. The stream was empty or EOF. */
throw new ParsingException("inStream is empty");
}
pbis.unread(buffer, 0, len);
if (len == PKCS7_MARKER.length && Arrays.equals(PKCS7_MARKER, buffer)) {
return fromPkcs7PemInputStream(pbis);
}
/* PKCS#7 bags have a byte 0x06 at position 4 in the stream. */
if (buffer[4] == 0x06) {
return fromPkcs7DerInputStream(pbis);
}
} catch (Exception e) {
if (markable) {
try {
inStream.reset();
} catch (IOException ignored) {
}
}
throw new ParsingException(e);
}
/*
* It wasn't, so just try to keep grabbing certificates until we
* can't anymore.
*/
final List coll = new ArrayList();
T c;
do {
/*
* If this stream supports marking, try to mark here in case
* there is an error during certificate generation.
*/
if (markable) {
inStream.mark(PUSHBACK_SIZE);
}
try {
c = generateItem(pbis);
coll.add(c);
} catch (ParsingException e) {
/*
* If this stream supports marking, attempt to reset it to
* the mark before the failure.
*/
if (markable) {
try {
inStream.reset();
} catch (IOException ignored) {
}
}
c = null;
}
} while (c != null);
return coll;
}
protected abstract T fromX509PemInputStream(InputStream pbis) throws ParsingException;
protected abstract T fromX509DerInputStream(InputStream pbis) throws ParsingException;
protected abstract List extends T> fromPkcs7PemInputStream(InputStream is)
throws ParsingException;
protected abstract List extends T> fromPkcs7DerInputStream(InputStream is)
throws ParsingException;
}
private Parser certificateParser =
new Parser() {
@Override
public OpenSSLX509Certificate fromX509PemInputStream(InputStream is)
throws ParsingException {
return OpenSSLX509Certificate.fromX509PemInputStream(is);
}
@Override
public OpenSSLX509Certificate fromX509DerInputStream(InputStream is)
throws ParsingException {
return OpenSSLX509Certificate.fromX509DerInputStream(is);
}
@Override
public List extends OpenSSLX509Certificate>
fromPkcs7PemInputStream(InputStream is) throws ParsingException {
return OpenSSLX509Certificate.fromPkcs7PemInputStream(is);
}
@Override
public List extends OpenSSLX509Certificate>
fromPkcs7DerInputStream(InputStream is) throws ParsingException {
return OpenSSLX509Certificate.fromPkcs7DerInputStream(is);
}
};
private Parser crlParser =
new Parser() {
@Override
public OpenSSLX509CRL fromX509PemInputStream(InputStream is)
throws ParsingException {
return OpenSSLX509CRL.fromX509PemInputStream(is);
}
@Override
public OpenSSLX509CRL fromX509DerInputStream(InputStream is)
throws ParsingException {
return OpenSSLX509CRL.fromX509DerInputStream(is);
}
@Override
public List extends OpenSSLX509CRL> fromPkcs7PemInputStream(InputStream is)
throws ParsingException {
return OpenSSLX509CRL.fromPkcs7PemInputStream(is);
}
@Override
public List extends OpenSSLX509CRL> fromPkcs7DerInputStream(InputStream is)
throws ParsingException {
return OpenSSLX509CRL.fromPkcs7DerInputStream(is);
}
};
@Override
public Certificate engineGenerateCertificate(InputStream inStream) throws CertificateException {
try {
return certificateParser.generateItem(inStream);
} catch (ParsingException e) {
throw new CertificateException(e);
}
}
@Override
public Collection extends Certificate> engineGenerateCertificates(
InputStream inStream) throws CertificateException {
try {
return certificateParser.generateItems(inStream);
} catch (ParsingException e) {
throw new CertificateException(e);
}
}
@Override
public CRL engineGenerateCRL(InputStream inStream) throws CRLException {
try {
return crlParser.generateItem(inStream);
} catch (ParsingException e) {
throw new CRLException(e);
}
}
@Override
public Collection extends CRL> engineGenerateCRLs(InputStream inStream) throws CRLException {
if (inStream == null) {
return Collections.emptyList();
}
try {
return crlParser.generateItems(inStream);
} catch (ParsingException e) {
throw new CRLException(e);
}
}
@Override
public Iterator engineGetCertPathEncodings() {
return OpenSSLX509CertPath.getEncodingsIterator();
}
@Override
public CertPath engineGenerateCertPath(InputStream inStream) throws CertificateException {
return OpenSSLX509CertPath.fromEncoding(inStream);
}
@Override
public CertPath engineGenerateCertPath(InputStream inStream, String encoding)
throws CertificateException {
return OpenSSLX509CertPath.fromEncoding(inStream, encoding);
}
@Override
public CertPath engineGenerateCertPath(List extends Certificate> certificates)
throws CertificateException {
final List filtered = new ArrayList(certificates.size());
for (int i = 0; i < certificates.size(); i++) {
final Certificate c = certificates.get(i);
if (!(c instanceof X509Certificate)) {
throw new CertificateException("Certificate not X.509 type at index " + i);
}
filtered.add((X509Certificate) c);
}
return new OpenSSLX509CertPath(filtered);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy