Merge "NativeCrypto: add OpenSSL X.509 certificate/CRLs"
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/NativeCrypto.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/NativeCrypto.java
index ed712df..ad14653 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/NativeCrypto.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/NativeCrypto.java
@@ -30,6 +30,7 @@
import java.security.cert.X509Certificate;
import java.security.interfaces.ECPrivateKey;
import java.util.ArrayList;
+import java.util.Calendar;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
@@ -338,6 +339,183 @@
throw new AssertionError(e);
}
}
+
+ public static native String X509_NAME_print_ex(long x509nameCtx, long flags);
+
+ // --- X509 ----------------------------------------------------------------
+
+ /** Used to request get_X509_GENERAL_NAME_stack get the "altname" field. */
+ public static final int GN_STACK_SUBJECT_ALT_NAME = 1;
+
+ /**
+ * Used to request get_X509_GENERAL_NAME_stack get the issuerAlternativeName
+ * extension.
+ */
+ public static final int GN_STACK_ISSUER_ALT_NAME = 2;
+
+ /**
+ * Used to request only non-critical types in get_X509*_ext_oids.
+ */
+ public static final int EXTENSION_TYPE_NON_CRITICAL = 0;
+
+ /**
+ * Used to request only critical types in get_X509*_ext_oids.
+ */
+ public static final int EXTENSION_TYPE_CRITICAL = 1;
+
+ public static native long d2i_X509_bio(long bioCtx);
+
+ public static native long PEM_read_bio_X509(long bioCtx);
+
+ public static native byte[] i2d_X509(long x509ctx);
+
+ /** Takes an X509 context not an X509_PUBKEY context. */
+ public static native byte[] i2d_X509_PUBKEY(long x509ctx);
+
+ public static native void X509_free(long x509ctx);
+
+ public static native int X509_cmp(long x509ctx1, long x509ctx2);
+
+ public static native int get_X509_hashCode(long x509ctx);
+
+ public static native void X509_print_ex(long bioCtx, long x509ctx, long nmflag, long certflag);
+
+ public static native byte[] X509_get_issuer_name(long x509ctx);
+
+ public static native byte[] X509_get_subject_name(long x509ctx);
+
+ public static native String get_X509_sig_alg_oid(long x509ctx);
+
+ public static native byte[] get_X509_sig_alg_parameter(long x509ctx);
+
+ public static native boolean[] get_X509_issuerUID(long x509ctx);
+
+ public static native boolean[] get_X509_subjectUID(long x509ctx);
+
+ public static native long X509_get_pubkey(long x509ctx) throws NoSuchAlgorithmException;
+
+ public static native String get_X509_pubkey_oid(long x509ctx);
+
+ public static native byte[] X509_get_ext_oid(long x509ctx, String oid);
+
+ public static native String[] get_X509_ext_oids(long x509ctx, int critical);
+
+ public static native Object[][] get_X509_GENERAL_NAME_stack(long x509ctx, int type);
+
+ public static native boolean[] get_X509_ex_kusage(long x509ctx);
+
+ public static native String[] get_X509_ex_xkusage(long x509ctx);
+
+ public static native int X509_check_ca(long x509ctx);
+
+ public static native int get_X509_ex_pathlen(long x509ctx);
+
+ public static native long X509_get_notBefore(long x509ctx);
+
+ public static native long X509_get_notAfter(long x509ctx);
+
+ public static native long X509_get_version(long x509ctx);
+
+ public static native byte[] X509_get_serialNumber(long x509ctx);
+
+ public static native void X509_verify(long x509ctx, long pkeyCtx);
+
+ public static native byte[] get_X509_cert_info_enc(long x509ctx);
+
+ public static native byte[] get_X509_signature(long x509ctx);
+
+ public static native int get_X509_ex_flags(long x509ctx);
+
+ // --- X509 EXFLAG ---------------------------------------------------------
+
+ public static final int EXFLAG_CRITICAL = 0x200;
+
+ // --- PKCS7 ---------------------------------------------------------------
+
+ /** Used as the "which" field in d2i_PKCS7_bio and PEM_read_bio_PKCS7. */
+ public static final int PKCS7_CERTS = 1;
+
+ /** Used as the "which" field in d2i_PKCS7_bio and PEM_read_bio_PKCS7. */
+ public static final int PKCS7_CRLS = 2;
+
+ /** Returns an array of X509 or X509_CRL pointers. */
+ public static native long[] d2i_PKCS7_bio(long bioCtx, int which);
+
+ /** Returns an array of X509 or X509_CRL pointers. */
+ public static native long[] PEM_read_bio_PKCS7(long bioCtx, int which);
+
+ // --- X509_CRL ------------------------------------------------------------
+
+ public static native long d2i_X509_CRL_bio(long bioCtx);
+
+ public static native long PEM_read_bio_X509_CRL(long bioCtx);
+
+ public static native byte[] i2d_X509_CRL(long x509CrlCtx);
+
+ public static native void X509_CRL_free(long x509CrlCtx);
+
+ public static native void X509_CRL_print(long bioCtx, long x509CrlCtx);
+
+ public static native String get_X509_CRL_sig_alg_oid(long x509CrlCtx);
+
+ public static native byte[] get_X509_CRL_sig_alg_parameter(long x509CrlCtx);
+
+ public static native byte[] X509_CRL_get_issuer_name(long x509CrlCtx);
+
+ /** Returns X509_REVOKED reference that is not duplicated! */
+ public static native long X509_CRL_get0_by_cert(long x509CrlCtx, long x509Ctx);
+
+ /** Returns X509_REVOKED reference that is not duplicated! */
+ public static native long X509_CRL_get0_by_serial(long x509CrlCtx, byte[] serial);
+
+ /** Returns an array of X509_REVOKED that are owned by the caller. */
+ public static native long[] X509_CRL_get_REVOKED(long x509CrlCtx);
+
+ public static native String[] get_X509_CRL_ext_oids(long x509ctx, int critical);
+
+ public static native byte[] X509_CRL_get_ext_oid(long x509CrlCtx, String oid);
+
+ public static native long X509_CRL_get_version(long x509CrlCtx);
+
+ public static native long X509_CRL_get_ext(long x509CrlCtx, String oid);
+
+ public static native byte[] get_X509_CRL_signature(long x509ctx);
+
+ public static native void X509_CRL_verify(long x509CrlCtx, long pkeyCtx);
+
+ public static native byte[] get_X509_CRL_crl_enc(long x509CrlCtx);
+
+ public static native long X509_CRL_get_lastUpdate(long x509CrlCtx);
+
+ public static native long X509_CRL_get_nextUpdate(long x509CrlCtx);
+
+ // --- X509_REVOKED --------------------------------------------------------
+
+ public static native long X509_REVOKED_dup(long x509RevokedCtx);
+
+ public static native byte[] i2d_X509_REVOKED(long x509RevokedCtx);
+
+ public static native String[] get_X509_REVOKED_ext_oids(long x509ctx, int critical);
+
+ public static native byte[] X509_REVOKED_get_ext_oid(long x509RevokedCtx, String oid);
+
+ public static native byte[] X509_REVOKED_get_serialNumber(long x509RevokedCtx);
+
+ public static native long X509_REVOKED_get_ext(long x509RevokedCtx, String oid);
+
+ /** Returns ASN1_TIME reference. */
+ public static native long get_X509_REVOKED_revocationDate(long x509RevokedCtx);
+
+ public static native void X509_REVOKED_print(long bioRef, long x509RevokedCtx);
+
+ // --- X509_EXTENSION ------------------------------------------------------
+
+ public static native int X509_supported_extension(long x509ExtensionRef);
+
+ // --- ASN1_TIME -----------------------------------------------------------
+
+ public static native void ASN1_TIME_to_Calendar(long asn1TimeCtx, Calendar cal);
+
// --- BIO stream creation -------------------------------------------------
public static native long create_BIO_InputStream(OpenSSLBIOInputStream is);
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLBIOInputStream.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLBIOInputStream.java
index c2109b6..823d30a 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLBIOInputStream.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLBIOInputStream.java
@@ -38,20 +38,29 @@
return ctx;
}
- public int readLine(byte[] buffer) throws IOException {
+ /**
+ * Similar to a {@code readLine} method, but matches what OpenSSL expects
+ * from a {@code BIO_gets} method.
+ */
+ public int gets(byte[] buffer) throws IOException {
if (buffer == null || buffer.length == 0) {
return 0;
}
int offset = 0;
- int inputByte = read();
- while (offset < buffer.length && inputByte != '\n' && inputByte != -1) {
- buffer[offset++] = (byte) inputByte;
+ int inputByte = 0;
+ while (offset < buffer.length) {
inputByte = read();
- }
+ if (inputByte == '\n' || inputByte == -1) {
+ if (offset == 0) {
+ // If we haven't read anything yet, ignore CRLF.
+ continue;
+ } else {
+ break;
+ }
+ }
- if (inputByte == '\n') {
- buffer[offset++] = '\n';
+ buffer[offset++] = (byte) inputByte;
}
return offset;
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLProvider.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLProvider.java
index 1c6a86e..7ac4022 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLProvider.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLProvider.java
@@ -226,5 +226,10 @@
put("Alg.Alias.Mac.1.2.840.113549.2.11", "HmacSHA512");
put("Alg.Alias.Mac.HMAC-SHA512", "HmacSHA512");
put("Alg.Alias.Mac.HMAC/SHA512", "HmacSHA512");
+
+ /* === Certificate === */
+
+ put("CertificateFactory.X509", OpenSSLX509CertificateFactory.class.getName());
+ put("Alg.Alias.CertificateFactory.X.509", "X509");
}
}
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLX509CRL.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLX509CRL.java
new file mode 100644
index 0000000..9d6b6b8
--- /dev/null
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLX509CRL.java
@@ -0,0 +1,393 @@
+/*
+ * Copyright (C) 2013 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.apache.harmony.xnet.provider.jsse;
+
+import org.apache.harmony.security.utils.AlgNameMapper;
+import org.apache.harmony.xnet.provider.jsse.OpenSSLX509CertificateFactory.ParsingException;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Principal;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.CRLException;
+import java.security.cert.Certificate;
+import java.security.cert.X509CRL;
+import java.security.cert.X509CRLEntry;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.TimeZone;
+
+import javax.security.auth.x500.X500Principal;
+
+public class OpenSSLX509CRL extends X509CRL {
+ private final long mContext;
+
+ private OpenSSLX509CRL(long ctx) {
+ mContext = ctx;
+ }
+
+ public static OpenSSLX509CRL fromX509DerInputStream(InputStream is) throws ParsingException {
+ final OpenSSLBIOInputStream bis = new OpenSSLBIOInputStream(is);
+
+ try {
+ final long crlCtx = NativeCrypto.d2i_X509_CRL_bio(bis.getBioContext());
+ if (crlCtx == 0) {
+ return null;
+ }
+ return new OpenSSLX509CRL(crlCtx);
+ } catch (Exception e) {
+ throw new ParsingException(e);
+ } finally {
+ NativeCrypto.BIO_free(bis.getBioContext());
+ }
+ }
+
+ public static List<OpenSSLX509CRL> fromPkcs7DerInputStream(InputStream is)
+ throws ParsingException {
+ OpenSSLBIOInputStream bis = new OpenSSLBIOInputStream(is);
+
+ final long[] certRefs;
+ try {
+ certRefs = NativeCrypto.d2i_PKCS7_bio(bis.getBioContext(), NativeCrypto.PKCS7_CRLS);
+ } catch (Exception e) {
+ throw new ParsingException(e);
+ } finally {
+ NativeCrypto.BIO_free(bis.getBioContext());
+ }
+
+ final List<OpenSSLX509CRL> certs = new ArrayList<OpenSSLX509CRL>(certRefs.length);
+ for (int i = 0; i < certRefs.length; i++) {
+ if (certRefs[i] == 0) {
+ continue;
+ }
+ certs.add(new OpenSSLX509CRL(certRefs[i]));
+ }
+ return certs;
+ }
+
+ public static OpenSSLX509CRL fromX509PemInputStream(InputStream is) throws ParsingException {
+ final OpenSSLBIOInputStream bis = new OpenSSLBIOInputStream(is);
+
+ try {
+ final long crlCtx = NativeCrypto.PEM_read_bio_X509_CRL(bis.getBioContext());
+ if (crlCtx == 0) {
+ return null;
+ }
+ return new OpenSSLX509CRL(crlCtx);
+ } catch (Exception e) {
+ throw new ParsingException(e);
+ } finally {
+ NativeCrypto.BIO_free(bis.getBioContext());
+ }
+ }
+
+ public static List<OpenSSLX509CRL> fromPkcs7PemInputStream(InputStream is)
+ throws ParsingException {
+ OpenSSLBIOInputStream bis = new OpenSSLBIOInputStream(is);
+
+ final long[] certRefs;
+ try {
+ certRefs = NativeCrypto.PEM_read_bio_PKCS7(bis.getBioContext(),
+ NativeCrypto.PKCS7_CRLS);
+ } catch (Exception e) {
+ throw new ParsingException(e);
+ } finally {
+ NativeCrypto.BIO_free(bis.getBioContext());
+ }
+
+ final List<OpenSSLX509CRL> certs = new ArrayList<OpenSSLX509CRL>(certRefs.length);
+ for (int i = 0; i < certRefs.length; i++) {
+ if (certRefs[i] == 0) {
+ continue;
+ }
+ certs.add(new OpenSSLX509CRL(certRefs[i]));
+ }
+ return certs;
+ }
+
+ @Override
+ public Set<String> getCriticalExtensionOIDs() {
+ String[] critOids =
+ NativeCrypto.get_X509_CRL_ext_oids(mContext, NativeCrypto.EXTENSION_TYPE_CRITICAL);
+
+ /*
+ * This API has a special case that if there are no extensions, we
+ * should return null. So if we have no critical extensions, we'll check
+ * non-critical extensions.
+ */
+ if ((critOids.length == 0)
+ && (NativeCrypto.get_X509_CRL_ext_oids(mContext,
+ NativeCrypto.EXTENSION_TYPE_NON_CRITICAL).length == 0)) {
+ return null;
+ }
+
+ return new HashSet<String>(Arrays.asList(critOids));
+ }
+
+ @Override
+ public byte[] getExtensionValue(String oid) {
+ return NativeCrypto.X509_CRL_get_ext_oid(mContext, oid);
+ }
+
+ @Override
+ public Set<String> getNonCriticalExtensionOIDs() {
+ String[] nonCritOids =
+ NativeCrypto.get_X509_CRL_ext_oids(mContext,
+ NativeCrypto.EXTENSION_TYPE_NON_CRITICAL);
+
+ /*
+ * This API has a special case that if there are no extensions, we
+ * should return null. So if we have no non-critical extensions, we'll
+ * check critical extensions.
+ */
+ if ((nonCritOids.length == 0)
+ && (NativeCrypto.get_X509_CRL_ext_oids(mContext,
+ NativeCrypto.EXTENSION_TYPE_CRITICAL).length == 0)) {
+ return null;
+ }
+
+ return new HashSet<String>(Arrays.asList(nonCritOids));
+ }
+
+ @Override
+ public boolean hasUnsupportedCriticalExtension() {
+ final String[] criticalOids =
+ NativeCrypto.get_X509_CRL_ext_oids(mContext, NativeCrypto.EXTENSION_TYPE_CRITICAL);
+ for (String oid : criticalOids) {
+ final long extensionRef = NativeCrypto.X509_CRL_get_ext(mContext, oid);
+ if (NativeCrypto.X509_supported_extension(extensionRef) != 1) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ @Override
+ public byte[] getEncoded() throws CRLException {
+ return NativeCrypto.i2d_X509_CRL(mContext);
+ }
+
+ private void verifyOpenSSL(OpenSSLKey pkey) throws CRLException, NoSuchAlgorithmException,
+ InvalidKeyException, NoSuchProviderException, SignatureException {
+ NativeCrypto.X509_CRL_verify(mContext, pkey.getPkeyContext());
+ }
+
+ private void verifyInternal(PublicKey key, String sigProvider) throws CRLException,
+ NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException,
+ SignatureException {
+ String sigAlg = getSigAlgName();
+ if (sigAlg == null) {
+ sigAlg = getSigAlgOID();
+ }
+
+ final Signature sig;
+ if (sigProvider == null) {
+ sig = Signature.getInstance(sigAlg);
+ } else {
+ sig = Signature.getInstance(sigAlg, sigProvider);
+ }
+
+ sig.initVerify(key);
+ sig.update(getTBSCertList());
+ if (!sig.verify(getSignature())) {
+ throw new SignatureException("signature did not verify");
+ }
+ }
+
+ @Override
+ public void verify(PublicKey key) throws CRLException, NoSuchAlgorithmException,
+ InvalidKeyException, NoSuchProviderException, SignatureException {
+ if (key instanceof OpenSSLKeyHolder) {
+ OpenSSLKey pkey = ((OpenSSLKeyHolder) key).getOpenSSLKey();
+ verifyOpenSSL(pkey);
+ return;
+ }
+
+ verifyInternal(key, null);
+ }
+
+ @Override
+ public void verify(PublicKey key, String sigProvider) throws CRLException,
+ NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException,
+ SignatureException {
+ verifyInternal(key, sigProvider);
+ }
+
+ @Override
+ public int getVersion() {
+ return (int) NativeCrypto.X509_CRL_get_version(mContext) + 1;
+ }
+
+ @Override
+ public Principal getIssuerDN() {
+ return getIssuerX500Principal();
+ }
+
+ @Override
+ public X500Principal getIssuerX500Principal() {
+ final byte[] issuer = NativeCrypto.X509_CRL_get_issuer_name(mContext);
+ return new X500Principal(issuer);
+ }
+
+ @Override
+ public Date getThisUpdate() {
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTimeZone(TimeZone.getTimeZone("UTC"));
+ NativeCrypto.ASN1_TIME_to_Calendar(NativeCrypto.X509_CRL_get_lastUpdate(mContext),
+ calendar);
+ return calendar.getTime();
+ }
+
+ @Override
+ public Date getNextUpdate() {
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTimeZone(TimeZone.getTimeZone("UTC"));
+ NativeCrypto.ASN1_TIME_to_Calendar(NativeCrypto.X509_CRL_get_nextUpdate(mContext),
+ calendar);
+ return calendar.getTime();
+ }
+
+ @Override
+ public X509CRLEntry getRevokedCertificate(BigInteger serialNumber) {
+ final long revokedRef = NativeCrypto.X509_CRL_get0_by_serial(mContext,
+ serialNumber.toByteArray());
+ if (revokedRef == 0) {
+ return null;
+ }
+
+ return new OpenSSLX509CRLEntry(NativeCrypto.X509_REVOKED_dup(revokedRef));
+ }
+
+ @Override
+ public X509CRLEntry getRevokedCertificate(X509Certificate certificate) {
+ if (certificate instanceof OpenSSLX509Certificate) {
+ OpenSSLX509Certificate osslCert = (OpenSSLX509Certificate) certificate;
+ final long x509RevokedRef = NativeCrypto.X509_CRL_get0_by_cert(mContext,
+ osslCert.getContext());
+
+ if (x509RevokedRef == 0) {
+ return null;
+ }
+
+ return new OpenSSLX509CRLEntry(NativeCrypto.X509_REVOKED_dup(x509RevokedRef));
+ }
+
+ return getRevokedCertificate(certificate.getSerialNumber());
+ }
+
+ @Override
+ public Set<? extends X509CRLEntry> getRevokedCertificates() {
+ final long[] entryRefs = NativeCrypto.X509_CRL_get_REVOKED(mContext);
+ if (entryRefs == null || entryRefs.length == 0) {
+ return null;
+ }
+
+ final Set<OpenSSLX509CRLEntry> crlSet = new HashSet<OpenSSLX509CRLEntry>();
+ for (long entryRef : entryRefs) {
+ crlSet.add(new OpenSSLX509CRLEntry(entryRef));
+ }
+
+ return crlSet;
+ }
+
+ @Override
+ public byte[] getTBSCertList() throws CRLException {
+ return NativeCrypto.get_X509_CRL_crl_enc(mContext);
+ }
+
+ @Override
+ public byte[] getSignature() {
+ return NativeCrypto.get_X509_CRL_signature(mContext);
+ }
+
+ @Override
+ public String getSigAlgName() {
+ return AlgNameMapper.map2AlgName(getSigAlgOID());
+ }
+
+ @Override
+ public String getSigAlgOID() {
+ return NativeCrypto.get_X509_CRL_sig_alg_oid(mContext);
+ }
+
+ @Override
+ public byte[] getSigAlgParams() {
+ return NativeCrypto.get_X509_CRL_sig_alg_parameter(mContext);
+ }
+
+ @Override
+ public boolean isRevoked(Certificate cert) {
+ if (!(cert instanceof X509Certificate)) {
+ return false;
+ }
+
+ final OpenSSLX509Certificate osslCert;
+ if (cert instanceof OpenSSLX509Certificate) {
+ osslCert = (OpenSSLX509Certificate) cert;
+ } else {
+ try {
+ osslCert = OpenSSLX509Certificate.fromX509DerInputStream(new ByteArrayInputStream(
+ cert.getEncoded()));
+ } catch (Exception e) {
+ throw new RuntimeException("cannot convert certificate", e);
+ }
+ }
+
+ final long x509RevokedRef = NativeCrypto.X509_CRL_get0_by_cert(mContext,
+ osslCert.getContext());
+
+ return x509RevokedRef != 0;
+ }
+
+ @Override
+ public String toString() {
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ final long bioCtx = NativeCrypto.create_BIO_OutputStream(os);
+ try {
+ NativeCrypto.X509_CRL_print(bioCtx, mContext);
+ return os.toString();
+ } finally {
+ NativeCrypto.BIO_free(bioCtx);
+ }
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ if (mContext != 0) {
+ NativeCrypto.X509_CRL_free(mContext);
+ }
+ } finally {
+ super.finalize();
+ }
+ }
+
+}
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLX509CRLEntry.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLX509CRLEntry.java
new file mode 100644
index 0000000..3655338
--- /dev/null
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLX509CRLEntry.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2013 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.apache.harmony.xnet.provider.jsse;
+
+import java.io.ByteArrayOutputStream;
+import java.math.BigInteger;
+import java.security.cert.CRLException;
+import java.security.cert.X509CRLEntry;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.TimeZone;
+
+public class OpenSSLX509CRLEntry extends X509CRLEntry {
+ private final long mContext;
+
+ OpenSSLX509CRLEntry(long ctx) {
+ mContext = ctx;
+ }
+
+ @Override
+ public Set<String> getCriticalExtensionOIDs() {
+ String[] critOids =
+ NativeCrypto.get_X509_REVOKED_ext_oids(mContext,
+ NativeCrypto.EXTENSION_TYPE_CRITICAL);
+
+ /*
+ * This API has a special case that if there are no extensions, we
+ * should return null. So if we have no critical extensions, we'll check
+ * non-critical extensions.
+ */
+ if ((critOids.length == 0)
+ && (NativeCrypto.get_X509_REVOKED_ext_oids(mContext,
+ NativeCrypto.EXTENSION_TYPE_NON_CRITICAL).length == 0)) {
+ return null;
+ }
+
+ return new HashSet<String>(Arrays.asList(critOids));
+ }
+
+ @Override
+ public byte[] getExtensionValue(String oid) {
+ return NativeCrypto.X509_REVOKED_get_ext_oid(mContext, oid);
+ }
+
+ @Override
+ public Set<String> getNonCriticalExtensionOIDs() {
+ String[] critOids =
+ NativeCrypto.get_X509_REVOKED_ext_oids(mContext,
+ NativeCrypto.EXTENSION_TYPE_NON_CRITICAL);
+
+ /*
+ * This API has a special case that if there are no extensions, we
+ * should return null. So if we have no non-critical extensions, we'll
+ * check critical extensions.
+ */
+ if ((critOids.length == 0)
+ && (NativeCrypto.get_X509_REVOKED_ext_oids(mContext,
+ NativeCrypto.EXTENSION_TYPE_CRITICAL).length == 0)) {
+ return null;
+ }
+
+ return new HashSet<String>(Arrays.asList(critOids));
+ }
+
+ @Override
+ public boolean hasUnsupportedCriticalExtension() {
+ final String[] criticalOids =
+ NativeCrypto.get_X509_REVOKED_ext_oids(mContext,
+ NativeCrypto.EXTENSION_TYPE_CRITICAL);
+ for (String oid : criticalOids) {
+ final long extensionRef = NativeCrypto.X509_REVOKED_get_ext(mContext, oid);
+ if (NativeCrypto.X509_supported_extension(extensionRef) != 1) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ @Override
+ public byte[] getEncoded() throws CRLException {
+ return NativeCrypto.i2d_X509_REVOKED(mContext);
+ }
+
+ @Override
+ public BigInteger getSerialNumber() {
+ return new BigInteger(NativeCrypto.X509_REVOKED_get_serialNumber(mContext));
+ }
+
+ @Override
+ public Date getRevocationDate() {
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTimeZone(TimeZone.getTimeZone("UTC"));
+ NativeCrypto.ASN1_TIME_to_Calendar(NativeCrypto.get_X509_REVOKED_revocationDate(mContext),
+ calendar);
+ return calendar.getTime();
+ }
+
+ @Override
+ public boolean hasExtensions() {
+ return (NativeCrypto.get_X509_REVOKED_ext_oids(mContext,
+ NativeCrypto.EXTENSION_TYPE_NON_CRITICAL).length != 0)
+ || (NativeCrypto.get_X509_REVOKED_ext_oids(mContext,
+ NativeCrypto.EXTENSION_TYPE_CRITICAL).length != 0);
+ }
+
+ @Override
+ public String toString() {
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ long bioCtx = NativeCrypto.create_BIO_OutputStream(os);
+ try {
+ NativeCrypto.X509_REVOKED_print(bioCtx, mContext);
+ return os.toString();
+ } finally {
+ NativeCrypto.BIO_free(bioCtx);
+ }
+ }
+}
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLX509Certificate.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLX509Certificate.java
new file mode 100644
index 0000000..bd7f2b2
--- /dev/null
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLX509Certificate.java
@@ -0,0 +1,476 @@
+/*
+ * 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.apache.harmony.xnet.provider.jsse;
+
+import org.apache.harmony.security.utils.AlgNameMapper;
+import org.apache.harmony.security.x509.X509PublicKey;
+import org.apache.harmony.xnet.provider.jsse.OpenSSLX509CertificateFactory.ParsingException;
+
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Principal;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.TimeZone;
+
+import javax.security.auth.x500.X500Principal;
+
+public class OpenSSLX509Certificate extends X509Certificate {
+ private final long mContext;
+
+ private OpenSSLX509Certificate(long ctx) {
+ mContext = ctx;
+ }
+
+ public static OpenSSLX509Certificate fromX509DerInputStream(InputStream is)
+ throws ParsingException {
+ final OpenSSLBIOInputStream bis = new OpenSSLBIOInputStream(is);
+
+ try {
+ final long certCtx = NativeCrypto.d2i_X509_bio(bis.getBioContext());
+ if (certCtx == 0) {
+ return null;
+ }
+ return new OpenSSLX509Certificate(certCtx);
+ } catch (Exception e) {
+ throw new ParsingException(e);
+ } finally {
+ NativeCrypto.BIO_free(bis.getBioContext());
+ }
+ }
+
+ public static List<OpenSSLX509Certificate> fromPkcs7DerInputStream(InputStream is)
+ throws ParsingException {
+ OpenSSLBIOInputStream bis = new OpenSSLBIOInputStream(is);
+
+ final long[] certRefs;
+ try {
+ certRefs = NativeCrypto.d2i_PKCS7_bio(bis.getBioContext(), NativeCrypto.PKCS7_CERTS);
+ } catch (Exception e) {
+ throw new ParsingException(e);
+ } finally {
+ NativeCrypto.BIO_free(bis.getBioContext());
+ }
+
+ final List<OpenSSLX509Certificate> certs = new ArrayList<OpenSSLX509Certificate>(
+ certRefs.length);
+ for (int i = 0; i < certRefs.length; i++) {
+ if (certRefs[i] == 0) {
+ continue;
+ }
+ certs.add(new OpenSSLX509Certificate(certRefs[i]));
+ }
+ return certs;
+ }
+
+ public static OpenSSLX509Certificate fromX509PemInputStream(InputStream is)
+ throws ParsingException {
+ final OpenSSLBIOInputStream bis = new OpenSSLBIOInputStream(is);
+
+ try {
+ final long certCtx = NativeCrypto.PEM_read_bio_X509(bis.getBioContext());
+ if (certCtx == 0L) {
+ return null;
+ }
+ return new OpenSSLX509Certificate(certCtx);
+ } catch (Exception e) {
+ throw new ParsingException(e);
+ } finally {
+ NativeCrypto.BIO_free(bis.getBioContext());
+ }
+ }
+
+ public static List<OpenSSLX509Certificate> fromPkcs7PemInputStream(InputStream is)
+ throws ParsingException {
+ OpenSSLBIOInputStream bis = new OpenSSLBIOInputStream(is);
+
+ final long[] certRefs;
+ try {
+ certRefs = NativeCrypto.PEM_read_bio_PKCS7(bis.getBioContext(),
+ NativeCrypto.PKCS7_CERTS);
+ } catch (Exception e) {
+ throw new ParsingException(e);
+ } finally {
+ NativeCrypto.BIO_free(bis.getBioContext());
+ }
+
+ final List<OpenSSLX509Certificate> certs = new ArrayList<OpenSSLX509Certificate>(
+ certRefs.length);
+ for (int i = 0; i < certRefs.length; i++) {
+ if (certRefs[i] == 0) {
+ continue;
+ }
+ certs.add(new OpenSSLX509Certificate(certRefs[i]));
+ }
+ return certs;
+ }
+
+ @Override
+ public Set<String> getCriticalExtensionOIDs() {
+ String[] critOids =
+ NativeCrypto.get_X509_ext_oids(mContext, NativeCrypto.EXTENSION_TYPE_CRITICAL);
+
+ /*
+ * This API has a special case that if there are no extensions, we
+ * should return null. So if we have no critical extensions, we'll check
+ * non-critical extensions.
+ */
+ if ((critOids.length == 0)
+ && (NativeCrypto.get_X509_ext_oids(mContext,
+ NativeCrypto.EXTENSION_TYPE_NON_CRITICAL).length == 0)) {
+ return null;
+ }
+
+ return new HashSet<String>(Arrays.asList(critOids));
+ }
+
+ @Override
+ public byte[] getExtensionValue(String oid) {
+ return NativeCrypto.X509_get_ext_oid(mContext, oid);
+ }
+
+ @Override
+ public Set<String> getNonCriticalExtensionOIDs() {
+ String[] nonCritOids =
+ NativeCrypto.get_X509_ext_oids(mContext, NativeCrypto.EXTENSION_TYPE_NON_CRITICAL);
+
+ /*
+ * This API has a special case that if there are no extensions, we
+ * should return null. So if we have no non-critical extensions, we'll
+ * check critical extensions.
+ */
+ if ((nonCritOids.length == 0)
+ && (NativeCrypto.get_X509_ext_oids(mContext,
+ NativeCrypto.EXTENSION_TYPE_CRITICAL).length == 0)) {
+ return null;
+ }
+
+ return new HashSet<String>(Arrays.asList(nonCritOids));
+ }
+
+ @Override
+ public boolean hasUnsupportedCriticalExtension() {
+ return (NativeCrypto.get_X509_ex_flags(mContext) & NativeCrypto.EXFLAG_CRITICAL) != 0;
+ }
+
+ @Override
+ public void checkValidity() throws CertificateExpiredException,
+ CertificateNotYetValidException {
+ checkValidity(new Date());
+ }
+
+ @Override
+ public void checkValidity(Date date) throws CertificateExpiredException,
+ CertificateNotYetValidException {
+ if (getNotBefore().compareTo(date) > 0) {
+ throw new CertificateNotYetValidException();
+ }
+
+ if (getNotAfter().compareTo(date) < 0) {
+ throw new CertificateExpiredException();
+ }
+ }
+
+ @Override
+ public int getVersion() {
+ return (int) NativeCrypto.X509_get_version(mContext) + 1;
+ }
+
+ @Override
+ public BigInteger getSerialNumber() {
+ return new BigInteger(NativeCrypto.X509_get_serialNumber(mContext));
+ }
+
+ @Override
+ public Principal getIssuerDN() {
+ return getIssuerX500Principal();
+ }
+
+ @Override
+ public Principal getSubjectDN() {
+ return getSubjectX500Principal();
+ }
+
+ @Override
+ public Date getNotBefore() {
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTimeZone(TimeZone.getTimeZone("UTC"));
+ NativeCrypto.ASN1_TIME_to_Calendar(NativeCrypto.X509_get_notBefore(mContext), calendar);
+ return calendar.getTime();
+ }
+
+ @Override
+ public Date getNotAfter() {
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTimeZone(TimeZone.getTimeZone("UTC"));
+ NativeCrypto.ASN1_TIME_to_Calendar(NativeCrypto.X509_get_notAfter(mContext), calendar);
+ return calendar.getTime();
+ }
+
+ @Override
+ public byte[] getTBSCertificate() throws CertificateEncodingException {
+ return NativeCrypto.get_X509_cert_info_enc(mContext);
+ }
+
+ @Override
+ public byte[] getSignature() {
+ return NativeCrypto.get_X509_signature(mContext);
+ }
+
+ @Override
+ public String getSigAlgName() {
+ return AlgNameMapper.map2AlgName(getSigAlgOID());
+ }
+
+ @Override
+ public String getSigAlgOID() {
+ return NativeCrypto.get_X509_sig_alg_oid(mContext);
+ }
+
+ @Override
+ public byte[] getSigAlgParams() {
+ return NativeCrypto.get_X509_sig_alg_parameter(mContext);
+ }
+
+ @Override
+ public boolean[] getIssuerUniqueID() {
+ return NativeCrypto.get_X509_issuerUID(mContext);
+ }
+
+ @Override
+ public boolean[] getSubjectUniqueID() {
+ return NativeCrypto.get_X509_subjectUID(mContext);
+ }
+
+ @Override
+ public boolean[] getKeyUsage() {
+ final boolean[] kusage = NativeCrypto.get_X509_ex_kusage(mContext);
+ if (kusage.length >= 9) {
+ return kusage;
+ }
+
+ final boolean resized[] = new boolean[9];
+ System.arraycopy(kusage, 0, resized, 0, kusage.length);
+ return resized;
+ }
+
+ @Override
+ public int getBasicConstraints() {
+ if (NativeCrypto.X509_check_ca(mContext) != 1) {
+ return -1;
+ }
+
+ final int pathLen = NativeCrypto.get_X509_ex_pathlen(mContext);
+ if (pathLen == -1) {
+ return Integer.MAX_VALUE;
+ }
+
+ return pathLen;
+ }
+
+ @Override
+ public byte[] getEncoded() throws CertificateEncodingException {
+ return NativeCrypto.i2d_X509(mContext);
+ }
+
+ private void verifyOpenSSL(OpenSSLKey pkey) throws CertificateException,
+ NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException,
+ SignatureException {
+ NativeCrypto.X509_verify(mContext, pkey.getPkeyContext());
+ }
+
+ private void verifyInternal(PublicKey key, String sigProvider) throws CertificateException,
+ NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException,
+ SignatureException {
+ String sigAlg = getSigAlgName();
+ if (sigAlg == null) {
+ sigAlg = getSigAlgOID();
+ }
+
+ final Signature sig;
+ if (sigProvider == null) {
+ sig = Signature.getInstance(sigAlg);
+ } else {
+ sig = Signature.getInstance(sigAlg, sigProvider);
+ }
+
+ sig.initVerify(key);
+ sig.update(getTBSCertificate());
+ if (!sig.verify(getSignature())) {
+ throw new SignatureException("signature did not verify");
+ }
+ }
+
+ @Override
+ public void verify(PublicKey key) throws CertificateException, NoSuchAlgorithmException,
+ InvalidKeyException, NoSuchProviderException, SignatureException {
+ if (key instanceof OpenSSLKeyHolder) {
+ OpenSSLKey pkey = ((OpenSSLKeyHolder) key).getOpenSSLKey();
+ verifyOpenSSL(pkey);
+ return;
+ }
+
+ verifyInternal(key, null);
+ }
+
+ @Override
+ public void verify(PublicKey key, String sigProvider) throws CertificateException,
+ NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException,
+ SignatureException {
+ verifyInternal(key, sigProvider);
+ }
+
+ @Override
+ public String toString() {
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ long bioCtx = NativeCrypto.create_BIO_OutputStream(os);
+ try {
+ NativeCrypto.X509_print_ex(bioCtx, mContext, 0, 0);
+ return os.toString();
+ } finally {
+ NativeCrypto.BIO_free(bioCtx);
+ }
+ }
+
+ @Override
+ public PublicKey getPublicKey() {
+ /* First try to generate the key from supported OpenSSL key types. */
+ try {
+ OpenSSLKey pkey = new OpenSSLKey(NativeCrypto.X509_get_pubkey(mContext));
+ return pkey.getPublicKey();
+ } catch (NoSuchAlgorithmException ignored) {
+ }
+
+ /* Try generating the key using other Java providers. */
+ String oid = NativeCrypto.get_X509_pubkey_oid(mContext);
+ byte[] encoded = NativeCrypto.i2d_X509_PUBKEY(mContext);
+ try {
+ KeyFactory kf = KeyFactory.getInstance(oid);
+ return kf.generatePublic(new X509EncodedKeySpec(encoded));
+ } catch (NoSuchAlgorithmException ignored) {
+ } catch (InvalidKeySpecException ignored) {
+ }
+
+ /*
+ * We couldn't find anything else, so just return a nearly-unusable
+ * X.509-encoded key.
+ */
+ return new X509PublicKey(oid, encoded, null);
+ }
+
+ @Override
+ public X500Principal getIssuerX500Principal() {
+ final byte[] issuer = NativeCrypto.X509_get_issuer_name(mContext);
+ return new X500Principal(issuer);
+ }
+
+ @Override
+ public X500Principal getSubjectX500Principal() {
+ final byte[] subject = NativeCrypto.X509_get_subject_name(mContext);
+ return new X500Principal(subject);
+ }
+
+ @Override
+ public List<String> getExtendedKeyUsage() throws CertificateParsingException {
+ String[] extUsage = NativeCrypto.get_X509_ex_xkusage(mContext);
+ if (extUsage == null) {
+ return null;
+ }
+
+ return Arrays.asList(extUsage);
+ }
+
+ private static Collection<List<?>> alternativeNameArrayToList(Object[][] altNameArray) {
+ if (altNameArray == null) {
+ return null;
+ }
+
+ Collection<List<?>> coll = new ArrayList<List<?>>(altNameArray.length);
+ for (int i = 0; i < altNameArray.length; i++) {
+ coll.add(Collections.unmodifiableList(Arrays.asList(altNameArray[i])));
+ }
+
+ return Collections.unmodifiableCollection(coll);
+ }
+
+ @Override
+ public Collection<List<?>> getSubjectAlternativeNames() throws CertificateParsingException {
+ return alternativeNameArrayToList(NativeCrypto.get_X509_GENERAL_NAME_stack(mContext,
+ NativeCrypto.GN_STACK_SUBJECT_ALT_NAME));
+ }
+
+ @Override
+ public Collection<List<?>> getIssuerAlternativeNames() throws CertificateParsingException {
+ return alternativeNameArrayToList(NativeCrypto.get_X509_GENERAL_NAME_stack(mContext,
+ NativeCrypto.GN_STACK_ISSUER_ALT_NAME));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other instanceof OpenSSLX509Certificate) {
+ OpenSSLX509Certificate o = (OpenSSLX509Certificate) other;
+
+ return NativeCrypto.X509_cmp(mContext, o.mContext) == 0;
+ }
+
+ return super.equals(other);
+ }
+
+ @Override
+ public int hashCode() {
+ /* Make this faster since we might be in hash-based structures. */
+ return NativeCrypto.get_X509_hashCode(mContext);
+ }
+
+ long getContext() {
+ return mContext;
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ if (mContext != 0) {
+ NativeCrypto.X509_free(mContext);
+ }
+ } finally {
+ super.finalize();
+ }
+ }
+}
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLX509CertificateFactory.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLX509CertificateFactory.java
new file mode 100644
index 0000000..29b1d25
--- /dev/null
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLX509CertificateFactory.java
@@ -0,0 +1,295 @@
+/*
+ * 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.apache.harmony.xnet.provider.jsse;
+
+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.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactorySpi;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+public class OpenSSLX509CertificateFactory extends CertificateFactorySpi {
+ private static final byte[] PKCS7_MARKER = "-----BEGIN PKCS7".getBytes();
+
+ private static final int PUSHBACK_SIZE = 64;
+
+ static class ParsingException extends Exception {
+ private static final long serialVersionUID = 8390802697728301325L;
+
+ public ParsingException(String message) {
+ super(message);
+ }
+
+ public ParsingException(Exception cause) {
+ super(cause);
+ }
+
+ public 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> {
+ public T generateItem(InputStream inStream) throws ParsingException {
+ 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);
+ }
+ }
+
+ public Collection<? extends T> generateItems(InputStream inStream)
+ throws ParsingException {
+ try {
+ if (inStream == null || 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<T> coll = new ArrayList<T>();
+ T c = null;
+ 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<OpenSSLX509Certificate> certificateParser =
+ new Parser<OpenSSLX509Certificate>() {
+ @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<OpenSSLX509CRL> crlParser =
+ new Parser<OpenSSLX509CRL>() {
+ @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);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ @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);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public Collection<? extends CRL> engineGenerateCRLs(InputStream inStream) throws CRLException {
+ try {
+ return crlParser.generateItems(inStream);
+ } catch (ParsingException e) {
+ throw new CRLException(e);
+ }
+ }
+}
diff --git a/luni/src/main/native/JniConstants.cpp b/luni/src/main/native/JniConstants.cpp
index b88eba9..6b3c7bd 100644
--- a/luni/src/main/native/JniConstants.cpp
+++ b/luni/src/main/native/JniConstants.cpp
@@ -24,6 +24,7 @@
jclass JniConstants::booleanClass;
jclass JniConstants::byteArrayClass;
jclass JniConstants::byteClass;
+jclass JniConstants::calendarClass;
jclass JniConstants::charsetICUClass;
jclass JniConstants::constructorClass;
jclass JniConstants::deflaterClass;
@@ -44,6 +45,8 @@
jclass JniConstants::methodClass;
jclass JniConstants::mutableIntClass;
jclass JniConstants::mutableLongClass;
+jclass JniConstants::objectClass;
+jclass JniConstants::objectArrayClass;
jclass JniConstants::outputStreamClass;
jclass JniConstants::parsePositionClass;
jclass JniConstants::patternSyntaxExceptionClass;
@@ -78,6 +81,7 @@
booleanClass = findClass(env, "java/lang/Boolean");
byteClass = findClass(env, "java/lang/Byte");
byteArrayClass = findClass(env, "[B");
+ calendarClass = findClass(env, "java/util/Calendar");
charsetICUClass = findClass(env, "java/nio/charset/CharsetICU");
constructorClass = findClass(env, "java/lang/reflect/Constructor");
deflaterClass = findClass(env, "java/util/zip/Deflater");
@@ -98,6 +102,8 @@
methodClass = findClass(env, "java/lang/reflect/Method");
mutableIntClass = findClass(env, "libcore/util/MutableInt");
mutableLongClass = findClass(env, "libcore/util/MutableLong");
+ objectClass = findClass(env, "java/lang/Object");
+ objectArrayClass = findClass(env, "[Ljava/lang/Object;");
outputStreamClass = findClass(env, "java/io/OutputStream");
parsePositionClass = findClass(env, "java/text/ParsePosition");
patternSyntaxExceptionClass = findClass(env, "java/util/regex/PatternSyntaxException");
diff --git a/luni/src/main/native/JniConstants.h b/luni/src/main/native/JniConstants.h
index bb5aebb..414cef8 100644
--- a/luni/src/main/native/JniConstants.h
+++ b/luni/src/main/native/JniConstants.h
@@ -45,6 +45,7 @@
static jclass booleanClass;
static jclass byteArrayClass;
static jclass byteClass;
+ static jclass calendarClass;
static jclass charsetICUClass;
static jclass constructorClass;
static jclass deflaterClass;
@@ -65,6 +66,8 @@
static jclass methodClass;
static jclass mutableIntClass;
static jclass mutableLongClass;
+ static jclass objectClass;
+ static jclass objectArrayClass;
static jclass outputStreamClass;
static jclass parsePositionClass;
static jclass patternSyntaxExceptionClass;
diff --git a/luni/src/main/native/org_apache_harmony_xnet_provider_jsse_NativeCrypto.cpp b/luni/src/main/native/org_apache_harmony_xnet_provider_jsse_NativeCrypto.cpp
index 1b68077..ec962d8 100644
--- a/luni/src/main/native/org_apache_harmony_xnet_provider_jsse_NativeCrypto.cpp
+++ b/luni/src/main/native/org_apache_harmony_xnet_provider_jsse_NativeCrypto.cpp
@@ -36,6 +36,7 @@
#include <openssl/rand.h>
#include <openssl/rsa.h>
#include <openssl/ssl.h>
+#include <openssl/x509v3.h>
#include "AsynchronousSocketCloseMonitor.h"
#include "JNIHelp.h"
@@ -68,7 +69,9 @@
static JavaVM* gJavaVM;
static jclass openSslOutputStreamClass;
+static jmethodID calendar_setMethod;
static jmethodID inputStream_readMethod;
+static jmethodID integer_valueOfMethod;
static jmethodID openSslInputStream_readLineMethod;
static jmethodID outputStream_writeMethod;
static jmethodID outputStream_flushMethod;
@@ -87,6 +90,13 @@
};
typedef UniquePtr<BIGNUM, BIGNUM_Delete> Unique_BIGNUM;
+struct ASN1_INTEGER_Delete {
+ void operator()(ASN1_INTEGER* p) const {
+ ASN1_INTEGER_free(p);
+ }
+};
+typedef UniquePtr<ASN1_INTEGER, ASN1_INTEGER_Delete> Unique_ASN1_INTEGER;
+
struct DH_Delete {
void operator()(DH* p) const {
DH_free(p);
@@ -157,6 +167,13 @@
};
typedef UniquePtr<RSA, RSA_Delete> Unique_RSA;
+struct ASN1_BIT_STRING_Delete {
+ void operator()(ASN1_BIT_STRING* p) const {
+ ASN1_BIT_STRING_free(p);
+ }
+};
+typedef UniquePtr<ASN1_BIT_STRING, ASN1_BIT_STRING_Delete> Unique_ASN1_BIT_STRING;
+
struct ASN1_OBJECT_Delete {
void operator()(ASN1_OBJECT* p) const {
ASN1_OBJECT_free(p);
@@ -164,6 +181,13 @@
};
typedef UniquePtr<ASN1_OBJECT, ASN1_OBJECT_Delete> Unique_ASN1_OBJECT;
+struct ASN1_GENERALIZEDTIME_Delete {
+ void operator()(ASN1_GENERALIZEDTIME* p) const {
+ ASN1_GENERALIZEDTIME_free(p);
+ }
+};
+typedef UniquePtr<ASN1_GENERALIZEDTIME, ASN1_GENERALIZEDTIME_Delete> Unique_ASN1_GENERALIZEDTIME;
+
struct SSL_Delete {
void operator()(SSL* p) const {
SSL_free(p);
@@ -221,6 +245,13 @@
};
typedef UniquePtr<X509_NAME, X509_NAME_Delete> Unique_X509_NAME;
+struct PKCS7_Delete {
+ void operator()(PKCS7* p) const {
+ PKCS7_free(p);
+ }
+};
+typedef UniquePtr<PKCS7, PKCS7_Delete> Unique_PKCS7;
+
struct sk_SSL_CIPHER_Delete {
void operator()(STACK_OF(SSL_CIPHER)* p) const {
sk_SSL_CIPHER_free(p);
@@ -242,6 +273,20 @@
};
typedef UniquePtr<STACK_OF(X509_NAME), sk_X509_NAME_Delete> Unique_sk_X509_NAME;
+struct sk_ASN1_OBJECT_Delete {
+ void operator()(STACK_OF(ASN1_OBJECT)* p) const {
+ sk_ASN1_OBJECT_free(p);
+ }
+};
+typedef UniquePtr<STACK_OF(ASN1_OBJECT), sk_ASN1_OBJECT_Delete> Unique_sk_ASN1_OBJECT;
+
+struct sk_GENERAL_NAME_Delete {
+ void operator()(STACK_OF(GENERAL_NAME)* p) const {
+ sk_GENERAL_NAME_free(p);
+ }
+};
+typedef UniquePtr<STACK_OF(GENERAL_NAME), sk_GENERAL_NAME_Delete> Unique_sk_GENERAL_NAME;
+
/**
* Many OpenSSL APIs take ownership of an argument on success but don't free the argument
* on failure. This means we need to tell our scoped pointers when we've transferred ownership,
@@ -280,6 +325,14 @@
}
/**
+ * Throws a InvalidKeyException with the given string as a message.
+ */
+static void throwInvalidKeyException(JNIEnv* env, const char* message) {
+ JNI_TRACE("throwInvalidKeyException %s", message);
+ jniThrowException(env, "java/security/InvalidKeyException", message);
+}
+
+/**
* Throws a SignatureException with the given string as a message.
*/
static void throwIllegalBlockSizeException(JNIEnv* env, const char* message) {
@@ -287,6 +340,14 @@
jniThrowException(env, "javax/crypto/IllegalBlockSizeException", message);
}
+/**
+ * Throws a NoSuchAlgorithmException with the given string as a message.
+ */
+static void throwNoSuchAlgorithmException(JNIEnv* env, const char* message) {
+ JNI_TRACE("throwUnknownAlgorithmException %s", message);
+ jniThrowException(env, "java/security/NoSuchAlgorithmException", message);
+}
+
/*
* Checks this thread's OpenSSL error queue and throws a RuntimeException if
* necessary.
@@ -315,10 +376,18 @@
throwBadPaddingException(env, message);
} else if (library == ERR_LIB_RSA && reason == RSA_R_DATA_GREATER_THAN_MOD_LEN) {
throwSignatureException(env, message);
+ } else if (library == ERR_LIB_RSA && reason == RSA_R_WRONG_SIGNATURE_LENGTH) {
+ throwSignatureException(env, message);
+ } else if (library == ERR_LIB_DSA && reason == DSA_R_PARAMETER_ENCODING_ERROR) {
+ throwInvalidKeyException(env, message);
+ } else if (library == ERR_LIB_ASN1 && reason == ASN1_R_WRONG_PUBLIC_KEY_TYPE) {
+ throwInvalidKeyException(env, message);
} else if (library == ERR_LIB_EVP && reason == EVP_R_BAD_DECRYPT) {
throwBadPaddingException(env, message);
} else if (library == ERR_LIB_EVP && reason == EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH) {
throwIllegalBlockSizeException(env, message);
+ } else if (library == ERR_LIB_X509 && reason == X509_R_UNSUPPORTED_ALGORITHM) {
+ throwNoSuchAlgorithmException(env, message);
} else {
jniThrowRuntimeException(env, message);
}
@@ -585,8 +654,14 @@
* inside. The "i2d_func" function pointer is a function of the "i2d_<TYPE>"
* from the OpenSSL ASN.1 API.
*/
-template<typename T>
-jbyteArray ASN1ToByteArray(JNIEnv* env, T* obj, int (*i2d_func)(T*, unsigned char**)) {
+template<typename T, int (*i2d_func)(T*, unsigned char**)>
+jbyteArray ASN1ToByteArray(JNIEnv* env, T* obj) {
+ if (obj == NULL) {
+ jniThrowNullPointerException(env, "ASN1 input == null");
+ JNI_TRACE("ASN1ToByteArray(%p) => null input", obj);
+ return NULL;
+ }
+
int derLen = i2d_func(obj, NULL);
if (derLen < 0) {
throwExceptionIfNecessary(env, "ASN1ToByteArray");
@@ -619,6 +694,28 @@
}
/**
+ * Converts ASN.1 BIT STRING to a jbooleanArray.
+ */
+jbooleanArray ASN1BitStringToBooleanArray(JNIEnv* env, ASN1_BIT_STRING* bitStr) {
+ int size = bitStr->length * 8;
+ if (bitStr->flags & ASN1_STRING_FLAG_BITS_LEFT) {
+ size -= bitStr->flags & 0x07;
+ }
+
+ ScopedLocalRef<jbooleanArray> bitsRef(env, env->NewBooleanArray(size));
+ if (bitsRef.get() == NULL) {
+ return NULL;
+ }
+
+ ScopedBooleanArrayRW bitsArray(env, bitsRef.get());
+ for (int i = 0; i < static_cast<int>(bitsArray.size()); i++) {
+ bitsArray[i] = ASN1_BIT_STRING_get_bit(bitStr, i);
+ }
+
+ return bitsRef.release();
+}
+
+/**
* BIO for InputStream
*/
class BIO_Stream {
@@ -689,6 +786,10 @@
}
int gets(char *buf, int len) {
+ if (len > PEM_LINE_LENGTH) {
+ len = PEM_LINE_LENGTH;
+ }
+
int read = read_internal(buf, len - 1, openSslInputStream_readLineMethod);
buf[read] = '\0';
JNI_TRACE("BIO::gets \"%s\"", buf);
@@ -725,6 +826,10 @@
return read;
}
+
+public:
+ /** Length of PEM-encoded line (64) plus CR plus NULL */
+ static const int PEM_LINE_LENGTH = 66;
};
class BIO_OutputStream : public BIO_Stream {
@@ -1471,7 +1576,7 @@
return NULL;
}
- return ASN1ToByteArray<PKCS8_PRIV_KEY_INFO>(env, pkcs8.get(), i2d_PKCS8_PRIV_KEY_INFO);
+ return ASN1ToByteArray<PKCS8_PRIV_KEY_INFO, i2d_PKCS8_PRIV_KEY_INFO>(env, pkcs8.get());
}
/*
@@ -1511,13 +1616,7 @@
static jbyteArray NativeCrypto_i2d_PUBKEY(JNIEnv* env, jclass, jlong pkeyRef) {
EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
JNI_TRACE("i2d_PUBKEY(%p)", pkey);
-
- if (pkey == NULL) {
- jniThrowNullPointerException(env, NULL);
- return NULL;
- }
-
- return ASN1ToByteArray<EVP_PKEY>(env, pkey, i2d_PUBKEY);
+ return ASN1ToByteArray<EVP_PKEY, i2d_PUBKEY>(env, pkey);
}
/*
@@ -2072,7 +2171,7 @@
int nid = EC_GROUP_get_curve_name(group);
if (nid == NID_undef) {
- JNI_TRACE("EC_GROUP_get_curve_name(%p) => unnamed curve", group, nid);
+ JNI_TRACE("EC_GROUP_get_curve_name(%p) => unnamed curve", group);
return NULL;
}
@@ -3398,45 +3497,23 @@
return env->NewStringUTF(longName);
}
-static jstring NativeCrypto_OBJ_txt2nid_oid(JNIEnv* env, jclass, jstring oidStr) {
- JNI_TRACE("OBJ_txt2nid_oid(%p)", oidStr);
-
- ScopedUtfChars oid(env, oidStr);
- if (oid.c_str() == NULL) {
- return NULL;
- }
-
- JNI_TRACE("OBJ_txt2nid_oid(%s)", oid.c_str());
-
- int nid = OBJ_txt2nid(oid.c_str());
- if (nid == NID_undef) {
- JNI_TRACE("OBJ_txt2nid_oid(%s) => NID_undef", oid.c_str());
- freeOpenSslErrorState();
- return NULL;
- }
-
- Unique_ASN1_OBJECT obj(OBJ_nid2obj(nid));
- if (obj.get() == NULL) {
- throwExceptionIfNecessary(env, "OBJ_nid2obj");
- return NULL;
- }
-
+static jstring ASN1_OBJECT_to_OID_string(JNIEnv* env, ASN1_OBJECT* obj) {
/*
* The OBJ_obj2txt API doesn't "measure" if you pass in NULL as the buffer.
* Just make a buffer that's large enough here. The documentation recommends
* 80 characters.
*/
char output[128];
- int ret = OBJ_obj2txt(output, sizeof(output), obj.get(), 1);
+ int ret = OBJ_obj2txt(output, sizeof(output), obj, 1);
if (ret < 0) {
- throwExceptionIfNecessary(env, "OBJ_obj2txt");
+ throwExceptionIfNecessary(env, "ASN1_OBJECT_to_OID_string");
return NULL;
} else if (size_t(ret) >= sizeof(output)) {
- jniThrowRuntimeException(env, "OBJ_obj2txt buffer too small");
+ jniThrowRuntimeException(env, "ASN1_OBJECT_to_OID_string buffer too small");
return NULL;
}
- JNI_TRACE("OBJ_txt2nid_oid(%s) => %s", oid.c_str(), output);
+ JNI_TRACE("ASN1_OBJECT_to_OID_string(%p) => %s", obj, output);
return env->NewStringUTF(output);
}
@@ -3561,6 +3638,1358 @@
BIO_free(bio);
}
+static jstring X509_NAME_to_jstring(JNIEnv* env, X509_NAME* name, unsigned long flags) {
+ JNI_TRACE("X509_NAME_to_jstring(%p)", name);
+
+ Unique_BIO buffer(BIO_new(BIO_s_mem()));
+ if (buffer.get() == NULL) {
+ jniThrowOutOfMemoryError(env, "Unable to allocate BIO");
+ JNI_TRACE("X509_NAME_to_jstring(%p) => threw error", name);
+ return NULL;
+ }
+
+ /* Don't interpret the string. */
+ flags &= ~(ASN1_STRFLGS_UTF8_CONVERT | ASN1_STRFLGS_ESC_MSB);
+
+ /* Write in given format and null terminate. */
+ X509_NAME_print_ex(buffer.get(), name, 0, flags);
+ BIO_write(buffer.get(), "\0", 1);
+
+ char *tmp;
+ BIO_get_mem_data(buffer.get(), &tmp);
+ JNI_TRACE("X509_NAME_to_jstring(%p) => \"%s\"", name, tmp);
+ return env->NewStringUTF(tmp);
+}
+
+
+/**
+ * Converts GENERAL_NAME items to the output format expected in
+ * X509Certificate#getSubjectAlternativeNames and
+ * X509Certificate#getIssuerAlternativeNames return.
+ */
+static jobject GENERAL_NAME_to_jobject(JNIEnv* env, GENERAL_NAME* gen) {
+ switch (gen->type) {
+ case GEN_EMAIL:
+ case GEN_DNS:
+ case GEN_URI:
+ return env->NewStringUTF(reinterpret_cast<char*>(ASN1_STRING_data(gen->d.ia5)));
+ case GEN_DIRNAME:
+ /* Write in RFC 2253 format */
+ return X509_NAME_to_jstring(env, gen->d.directoryName, XN_FLAG_RFC2253);
+ case GEN_IPADD: {
+ const void *ip = reinterpret_cast<const void *>(gen->d.ip->data);
+ if (gen->d.ip->length == 4) {
+ // IPv4
+ UniquePtr<char[]> buffer(new char[INET_ADDRSTRLEN]);
+ if (inet_ntop(AF_INET, ip, buffer.get(), INET_ADDRSTRLEN) != NULL) {
+ JNI_TRACE("GENERAL_NAME_to_jobject(%p) => IPv4 %s", gen, buffer.get());
+ return env->NewStringUTF(buffer.get());
+ } else {
+ JNI_TRACE("GENERAL_NAME_to_jobject(%p) => IPv4 failed %s", gen, strerror(errno));
+ }
+ } else if (gen->d.ip->length == 16) {
+ // IPv6
+ UniquePtr<char[]> buffer(new char[INET6_ADDRSTRLEN]);
+ if (inet_ntop(AF_INET6, ip, buffer.get(), INET6_ADDRSTRLEN) != NULL) {
+ JNI_TRACE("GENERAL_NAME_to_jobject(%p) => IPv6 %s", gen, buffer.get());
+ return env->NewStringUTF(buffer.get());
+ } else {
+ JNI_TRACE("GENERAL_NAME_to_jobject(%p) => IPv6 failed %s", gen, strerror(errno));
+ }
+ }
+ break;
+ }
+ case GEN_RID:
+ return ASN1_OBJECT_to_OID_string(env, gen->d.registeredID);
+ case GEN_OTHERNAME:
+ case GEN_X400:
+ default:
+ return ASN1ToByteArray<GENERAL_NAME, i2d_GENERAL_NAME>(env, gen);
+ }
+
+ return NULL;
+}
+
+#define GN_STACK_SUBJECT_ALT_NAME 1
+#define GN_STACK_ISSUER_ALT_NAME 2
+
+static jobjectArray NativeCrypto_get_X509_GENERAL_NAME_stack(JNIEnv* env, jclass, jlong x509Ref,
+ jint type) {
+ X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
+ JNI_TRACE("get_X509_GENERAL_NAME_stack(%p, %d)", x509, type);
+
+ if (x509 == NULL) {
+ jniThrowNullPointerException(env, "x509 == null");
+ JNI_TRACE("get_X509_GENERAL_NAME_stack(%p, %d) => x509 == null", x509, type);
+ return NULL;
+ }
+
+ X509_check_ca(x509);
+
+ STACK_OF(GENERAL_NAME)* gn_stack;
+ Unique_sk_GENERAL_NAME stackHolder;
+ if (type == GN_STACK_SUBJECT_ALT_NAME) {
+ gn_stack = x509->altname;
+ } else if (type == GN_STACK_ISSUER_ALT_NAME) {
+ stackHolder.reset(
+ static_cast<STACK_OF(GENERAL_NAME)*>(X509_get_ext_d2i(x509, NID_issuer_alt_name,
+ NULL, NULL)));
+ gn_stack = stackHolder.get();
+ } else {
+ JNI_TRACE("get_X509_GENERAL_NAME_stack(%p, %d) => unknown type", x509, type);
+ return NULL;
+ }
+
+ int count = sk_GENERAL_NAME_num(gn_stack);
+ if (count <= 0) {
+ JNI_TRACE("get_X509_GENERAL_NAME_stack(%p, %d) => null (no entries)", x509, type);
+ return NULL;
+ }
+
+ /*
+ * Keep track of how many originally so we can ignore any invalid
+ * values later.
+ */
+ const int origCount = count;
+
+ ScopedLocalRef<jobjectArray> joa(env, env->NewObjectArray(count,
+ JniConstants::objectArrayClass, NULL));
+ for (int i = 0, j = 0; i < origCount; i++, j++) {
+ GENERAL_NAME* gen = sk_GENERAL_NAME_value(gn_stack, i);
+ ScopedLocalRef<jobject> val(env, GENERAL_NAME_to_jobject(env, gen));
+
+ /*
+ * If it's NULL, we'll have to skip this, reduce the number of total
+ * entries, and fix up the array later.
+ */
+ if (val.get() == NULL) {
+ j--;
+ count--;
+ continue;
+ }
+
+ ScopedLocalRef<jobjectArray> item(env, env->NewObjectArray(2, JniConstants::objectClass,
+ NULL));
+
+ ScopedLocalRef<jobject> type(env, env->CallStaticObjectMethod(JniConstants::integerClass,
+ integer_valueOfMethod, gen->type));
+ env->SetObjectArrayElement(item.get(), 0, type.get());
+ env->SetObjectArrayElement(item.get(), 1, val.get());
+
+ env->SetObjectArrayElement(joa.get(), j, item.get());
+ }
+
+ if (count == 0) {
+ JNI_TRACE("get_X509_GENERAL_NAME_stack(%p, %d) shrunk from %d to 0; returning NULL",
+ x509, type, origCount);
+ joa.reset(NULL);
+ } else if (origCount != count) {
+ JNI_TRACE("get_X509_GENERAL_NAME_stack(%p, %d) shrunk from %d to %d", x509, type,
+ origCount, count);
+
+ ScopedLocalRef<jobjectArray> joa_copy(env, env->NewObjectArray(count,
+ JniConstants::objectArrayClass, NULL));
+
+ for (int i = 0; i < count; i++) {
+ ScopedLocalRef<jobject> item(env, env->GetObjectArrayElement(joa.get(), i));
+ env->SetObjectArrayElement(joa_copy.get(), i, item.get());
+ }
+
+ joa.reset(joa_copy.release());
+ }
+
+ JNI_TRACE("get_X509_GENERAL_NAME_stack(%p, %d) => %d entries", x509, type, count);
+ return joa.release();
+}
+
+static jlong NativeCrypto_X509_get_notBefore(JNIEnv* env, jclass, jlong x509Ref) {
+ X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
+ JNI_TRACE("X509_get_notBefore(%p)", x509);
+
+ if (x509 == NULL) {
+ jniThrowNullPointerException(env, "x509 == null");
+ JNI_TRACE("X509_get_notBefore(%p) => x509 == null", x509);
+ return 0;
+ }
+
+ ASN1_TIME* notBefore = X509_get_notBefore(x509);
+ JNI_TRACE("X509_get_notBefore(%p) => %p", x509, notBefore);
+ return reinterpret_cast<uintptr_t>(notBefore);
+}
+
+static jlong NativeCrypto_X509_get_notAfter(JNIEnv* env, jclass, jlong x509Ref) {
+ X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
+ JNI_TRACE("X509_get_notAfter(%p)", x509);
+
+ if (x509 == NULL) {
+ jniThrowNullPointerException(env, "x509 == null");
+ JNI_TRACE("X509_get_notAfter(%p) => x509 == null", x509);
+ return 0;
+ }
+
+ ASN1_TIME* notAfter = X509_get_notAfter(x509);
+ JNI_TRACE("X509_get_notAfter(%p) => %p", x509, notAfter);
+ return reinterpret_cast<uintptr_t>(notAfter);
+}
+
+static long NativeCrypto_X509_get_version(JNIEnv*, jclass, jlong x509Ref) {
+ X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
+ JNI_TRACE("X509_get_version(%p)", x509);
+
+ long version = X509_get_version(x509);
+ JNI_TRACE("X509_get_version(%p) => %ld", x509, version);
+ return version;
+}
+
+template<typename T>
+static jbyteArray get_X509Type_serialNumber(JNIEnv* env, T* x509Type, ASN1_INTEGER* (*get_serial_func)(T*)) {
+ JNI_TRACE("get_X509Type_serialNumber(%p)", x509Type);
+
+ if (x509Type == NULL) {
+ jniThrowNullPointerException(env, "x509Type == null");
+ JNI_TRACE("get_X509Type_serialNumber(%p) => x509Type == null", x509Type);
+ return NULL;
+ }
+
+ ASN1_INTEGER* serialNumber = get_serial_func(x509Type);
+ Unique_BIGNUM serialBn(ASN1_INTEGER_to_BN(serialNumber, NULL));
+ if (serialBn.get() == NULL) {
+ JNI_TRACE("X509_get_serialNumber(%p) => threw exception", x509Type);
+ return NULL;
+ }
+
+ ScopedLocalRef<jbyteArray> serialArray(env, bignumToArray(env, serialBn.get(), "serialBn"));
+ if (env->ExceptionCheck()) {
+ JNI_TRACE("X509_get_serialNumber(%p) => threw exception", x509Type);
+ return NULL;
+ }
+
+ JNI_TRACE("X509_get_serialNumber(%p) => %p", x509Type, serialArray.get());
+ return serialArray.release();
+}
+
+/* OpenSSL includes set_serialNumber but not get. */
+#if !defined(X509_REVOKED_get_serialNumber)
+static ASN1_INTEGER* X509_REVOKED_get_serialNumber(X509_REVOKED* x) {
+ return x->serialNumber;
+}
+#endif
+
+static jbyteArray NativeCrypto_X509_get_serialNumber(JNIEnv* env, jclass, jlong x509Ref) {
+ X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
+ JNI_TRACE("X509_get_serialNumber(%p)", x509);
+ return get_X509Type_serialNumber<X509>(env, x509, X509_get_serialNumber);
+}
+
+static jbyteArray NativeCrypto_X509_REVOKED_get_serialNumber(JNIEnv* env, jclass, jlong x509RevokedRef) {
+ X509_REVOKED* revoked = reinterpret_cast<X509_REVOKED*>(static_cast<uintptr_t>(x509RevokedRef));
+ JNI_TRACE("X509_REVOKED_get_serialNumber(%p)", revoked);
+ return get_X509Type_serialNumber<X509_REVOKED>(env, revoked, X509_REVOKED_get_serialNumber);
+}
+
+static void NativeCrypto_X509_verify(JNIEnv* env, jclass, jlong x509Ref, jlong pkeyRef) {
+ X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
+ EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
+ JNI_TRACE("X509_verify(%p, %p)", x509, pkey);
+
+ if (x509 == NULL) {
+ jniThrowNullPointerException(env, "x509 == null");
+ JNI_TRACE("X509_verify(%p, %p) => x509 == null", x509, pkey);
+ return;
+ }
+
+ if (pkey == NULL) {
+ jniThrowNullPointerException(env, "pkey == null");
+ JNI_TRACE("X509_verify(%p, %p) => pkey == null", x509, pkey);
+ return;
+ }
+
+ if (X509_verify(x509, pkey) != 1) {
+ throwExceptionIfNecessary(env, "X509_verify");
+ JNI_TRACE("X509_verify(%p, %p) => verify failure", x509, pkey);
+ } else {
+ JNI_TRACE("X509_verify(%p, %p) => verify success", x509, pkey);
+ }
+}
+
+static jbyteArray NativeCrypto_get_X509_cert_info_enc(JNIEnv* env, jclass, jlong x509Ref) {
+ X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
+ JNI_TRACE("get_X509_cert_info_enc(%p)", x509);
+ return ASN1ToByteArray<X509_CINF, i2d_X509_CINF>(env, x509->cert_info);
+}
+
+static jint NativeCrypto_get_X509_ex_flags(JNIEnv* env, jclass, jlong x509Ref) {
+ X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
+ JNI_TRACE("get_X509_ex_flags(%p)", x509);
+
+ if (x509 == NULL) {
+ jniThrowNullPointerException(env, "x509 == null");
+ JNI_TRACE("get_X509_ex_flags(%p) => x509 == null", x509);
+ return 0;
+ }
+
+ X509_check_ca(x509);
+
+ return x509->ex_flags;
+}
+
+static void get_X509_signature(X509 *x509, ASN1_BIT_STRING** signature) {
+ *signature = x509->signature;
+}
+
+static void get_X509_CRL_signature(X509_CRL *crl, ASN1_BIT_STRING** signature) {
+ *signature = crl->signature;
+}
+
+template<typename T>
+static jbyteArray get_X509Type_signature(JNIEnv* env, T* x509Type, void (*get_signature_func)(T*, ASN1_BIT_STRING**)) {
+ JNI_TRACE("get_X509Type_signature(%p)", x509Type);
+
+ if (x509Type == NULL) {
+ jniThrowNullPointerException(env, "x509Type == null");
+ JNI_TRACE("get_X509Type_signature(%p) => x509Type == null", x509Type);
+ return NULL;
+ }
+
+ ASN1_BIT_STRING* signature;
+ get_signature_func(x509Type, &signature);
+
+ ScopedLocalRef<jbyteArray> signatureArray(env, env->NewByteArray(signature->length));
+ if (env->ExceptionCheck()) {
+ JNI_TRACE("get_X509Type_signature(%p) => threw exception", x509Type);
+ return NULL;
+ }
+
+ ScopedByteArrayRW signatureBytes(env, signatureArray.get());
+ if (signatureBytes.get() == NULL) {
+ JNI_TRACE("get_X509Type_signature(%p) => using byte array failed", x509Type);
+ return NULL;
+ }
+
+ memcpy(signatureBytes.get(), signature->data, signature->length);
+
+ JNI_TRACE("get_X509Type_signature(%p) => %p (%d bytes)", x509Type, signatureArray.get(),
+ signature->length);
+ return signatureArray.release();
+}
+
+static jbyteArray NativeCrypto_get_X509_signature(JNIEnv* env, jclass, jlong x509Ref) {
+ X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
+ JNI_TRACE("get_X509_signature(%p)", x509);
+ return get_X509Type_signature<X509>(env, x509, get_X509_signature);
+}
+
+static jbyteArray NativeCrypto_get_X509_CRL_signature(JNIEnv* env, jclass, jlong x509CrlRef) {
+ X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef));
+ JNI_TRACE("get_X509_CRL_signature(%p)", crl);
+ return get_X509Type_signature<X509_CRL>(env, crl, get_X509_CRL_signature);
+}
+
+static jlong NativeCrypto_X509_CRL_get0_by_cert(JNIEnv* env, jclass, jlong x509crlRef, jlong x509Ref) {
+ X509_CRL* x509crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509crlRef));
+ X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
+ JNI_TRACE("X509_CRL_get0_by_cert(%p, %p)", x509crl, x509);
+
+ if (x509crl == NULL) {
+ jniThrowNullPointerException(env, "x509crl == null");
+ JNI_TRACE("X509_CRL_get0_by_cert(%p, %p) => x509crl == null", x509crl, x509);
+ return 0;
+ } else if (x509 == NULL) {
+ jniThrowNullPointerException(env, "x509 == null");
+ JNI_TRACE("X509_CRL_get0_by_cert(%p, %p) => x509 == null", x509crl, x509);
+ return 0;
+ }
+
+ X509_REVOKED* revoked = NULL;
+ int ret = X509_CRL_get0_by_cert(x509crl, &revoked, x509);
+ if (ret == 0) {
+ JNI_TRACE("X509_CRL_get0_by_cert(%p, %p) => none", x509crl, x509);
+ return 0;
+ }
+
+ JNI_TRACE("X509_CRL_get0_by_cert(%p, %p) => %p", x509crl, x509, revoked);
+ return reinterpret_cast<uintptr_t>(revoked);
+}
+
+static jlong NativeCrypto_X509_CRL_get0_by_serial(JNIEnv* env, jclass, jlong x509crlRef, jbyteArray serialArray) {
+ X509_CRL* x509crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509crlRef));
+ JNI_TRACE("X509_CRL_get0_by_serial(%p, %p)", x509crl, serialArray);
+
+ if (x509crl == NULL) {
+ jniThrowNullPointerException(env, "x509crl == null");
+ JNI_TRACE("X509_CRL_get0_by_serial(%p, %p) => crl == null", x509crl, serialArray);
+ return 0;
+ }
+
+ Unique_BIGNUM serialBn(BN_new());
+ if (serialBn.get() == NULL) {
+ JNI_TRACE("X509_CRL_get0_by_serial(%p, %p) => BN allocation failed", x509crl, serialArray);
+ return 0;
+ }
+
+ BIGNUM* serialBare = serialBn.get();
+ if (!arrayToBignum(env, serialArray, &serialBare)) {
+ if (!env->ExceptionCheck()) {
+ jniThrowNullPointerException(env, "serial == null");
+ }
+ JNI_TRACE("X509_CRL_get0_by_serial(%p, %p) => BN conversion failed", x509crl, serialArray);
+ return 0;
+ }
+
+ Unique_ASN1_INTEGER serialInteger(BN_to_ASN1_INTEGER(serialBn.get(), NULL));
+ if (serialInteger.get() == NULL) {
+ JNI_TRACE("X509_CRL_get0_by_serial(%p, %p) => BN conversion failed", x509crl, serialArray);
+ return 0;
+ }
+
+ X509_REVOKED* revoked = NULL;
+ int ret = X509_CRL_get0_by_serial(x509crl, &revoked, serialInteger.get());
+ if (ret == 0) {
+ JNI_TRACE("X509_CRL_get0_by_serial(%p, %p) => none", x509crl, serialArray);
+ return 0;
+ }
+
+ JNI_TRACE("X509_CRL_get0_by_cert(%p, %p) => %p", x509crl, serialArray, revoked);
+ return reinterpret_cast<uintptr_t>(revoked);
+}
+
+
+/* This appears to be missing from OpenSSL. */
+#if !defined(X509_REVOKED_dup)
+X509_REVOKED* X509_REVOKED_dup(X509_REVOKED* x) {
+ return reinterpret_cast<X509_REVOKED*>(ASN1_item_dup(ASN1_ITEM_rptr(X509_REVOKED), x));
+}
+#endif
+
+static jlongArray NativeCrypto_X509_CRL_get_REVOKED(JNIEnv* env, jclass, jlong x509CrlRef) {
+ X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef));
+ JNI_TRACE("X509_CRL_get_REVOKED(%p)", crl);
+
+ if (crl == NULL) {
+ jniThrowNullPointerException(env, "crl == null");
+ return NULL;
+ }
+
+ STACK_OF(X509_REVOKED)* stack = X509_CRL_get_REVOKED(crl);
+ if (stack == NULL) {
+ JNI_TRACE("X509_CRL_get_REVOKED(%p) => stack is null", crl);
+ return NULL;
+ }
+
+ size_t size = sk_X509_REVOKED_num(stack);
+
+ ScopedLocalRef<jlongArray> revokedArray(env, env->NewLongArray(size));
+ ScopedLongArrayRW revoked(env, revokedArray.get());
+ for (size_t i = 0; i < size; i++) {
+ X509_REVOKED* item = reinterpret_cast<X509_REVOKED*>(sk_X509_REVOKED_value(stack, i));
+ revoked[i] = reinterpret_cast<uintptr_t>(X509_REVOKED_dup(item));
+ }
+
+ JNI_TRACE("X509_CRL_get_REVOKED(%p) => %p [size=%d]", stack, revokedArray.get(), size);
+ return revokedArray.release();
+}
+
+static jbyteArray NativeCrypto_i2d_X509_CRL(JNIEnv* env, jclass, jlong x509CrlRef) {
+ X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef));
+ JNI_TRACE("i2d_X509_CRL(%p)", crl);
+ return ASN1ToByteArray<X509_CRL, i2d_X509_CRL>(env, crl);
+}
+
+static void NativeCrypto_X509_CRL_free(JNIEnv* env, jclass, jlong x509CrlRef) {
+ X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef));
+ JNI_TRACE("X509_CRL_free(%p)", crl);
+
+ if (crl == NULL) {
+ jniThrowNullPointerException(env, "crl == null");
+ JNI_TRACE("X509_CRL_free(%p) => crl == null", crl);
+ return;
+ }
+
+ X509_CRL_free(crl);
+}
+
+static void NativeCrypto_X509_CRL_print(JNIEnv* env, jclass, jlong bioRef, jlong x509CrlRef) {
+ BIO* bio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(bioRef));
+ X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef));
+ JNI_TRACE("X509_CRL_print(%p, %p)", bio, crl);
+
+ if (bio == NULL) {
+ jniThrowNullPointerException(env, "bio == null");
+ JNI_TRACE("X509_CRL_print(%p, %p) => bio == null", bio, crl);
+ return;
+ }
+
+ if (crl == NULL) {
+ jniThrowNullPointerException(env, "crl == null");
+ JNI_TRACE("X509_CRL_print(%p, %p) => crl == null", bio, crl);
+ return;
+ }
+
+ X509_CRL_print(bio, crl);
+ JNI_TRACE("X509_CRL_print(%p, %p) => success", bio, crl);
+}
+
+static jstring NativeCrypto_get_X509_CRL_sig_alg_oid(JNIEnv* env, jclass, jlong x509CrlRef) {
+ X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef));
+ JNI_TRACE("get_X509_CRL_sig_alg_oid(%p)", crl);
+
+ if (crl == NULL || crl->sig_alg == NULL) {
+ jniThrowNullPointerException(env, "crl == NULL || crl->sig_alg == NULL");
+ JNI_TRACE("get_X509_CRL_sig_alg_oid(%p) => crl == NULL", crl);
+ return NULL;
+ }
+
+ return ASN1_OBJECT_to_OID_string(env, crl->sig_alg->algorithm);
+}
+
+static jbyteArray NativeCrypto_get_X509_CRL_sig_alg_parameter(JNIEnv* env, jclass, jlong x509CrlRef) {
+ X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef));
+ JNI_TRACE("get_X509_CRL_sig_alg_parameter(%p)", crl);
+
+ if (crl == NULL) {
+ jniThrowNullPointerException(env, "crl == null");
+ JNI_TRACE("get_X509_CRL_sig_alg_parameter(%p) => crl == null", crl);
+ return NULL;
+ }
+
+ if (crl->sig_alg->parameter == NULL) {
+ JNI_TRACE("get_X509_CRL_sig_alg_parameter(%p) => null", crl);
+ return NULL;
+ }
+
+ return ASN1ToByteArray<ASN1_TYPE, i2d_ASN1_TYPE>(env, crl->sig_alg->parameter);
+}
+
+static jbyteArray NativeCrypto_X509_CRL_get_issuer_name(JNIEnv* env, jclass, jlong x509CrlRef) {
+ X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef));
+ JNI_TRACE("X509_CRL_get_issuer_name(%p)", crl);
+ return ASN1ToByteArray<X509_NAME, i2d_X509_NAME>(env, X509_CRL_get_issuer(crl));
+}
+
+static long NativeCrypto_X509_CRL_get_version(JNIEnv*, jclass, jlong x509CrlRef) {
+ X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef));
+ JNI_TRACE("X509_CRL_get_version(%p)", crl);
+
+ long version = X509_CRL_get_version(crl);
+ JNI_TRACE("X509_CRL_get_version(%p) => %ld", crl, version);
+ return version;
+}
+
+template<typename T, int (*get_ext_by_OBJ_func)(T*, ASN1_OBJECT*, int),
+ X509_EXTENSION* (*get_ext_func)(T*, int)>
+static X509_EXTENSION *X509Type_get_ext(JNIEnv* env, T* x509Type, jstring oidString) {
+ JNI_TRACE("X509Type_get_ext(%p)", x509Type);
+
+ if (x509Type == NULL) {
+ jniThrowNullPointerException(env, "x509 == null");
+ return NULL;
+ }
+
+ ScopedUtfChars oid(env, oidString);
+ if (oid.c_str() == NULL) {
+ return NULL;
+ }
+
+ Unique_ASN1_OBJECT asn1(OBJ_txt2obj(oid.c_str(), 1));
+ if (asn1.get() == NULL) {
+ JNI_TRACE("X509Type_get_ext(%p, %s) => oid conversion failed", x509Type, oid.c_str());
+ freeOpenSslErrorState();
+ return NULL;
+ }
+
+ int extIndex = get_ext_by_OBJ_func(x509Type, asn1.get(), -1);
+ if (extIndex == -1) {
+ JNI_TRACE("X509Type_get_ext(%p, %s) => ext not found", x509Type, oid.c_str());
+ return NULL;
+ }
+
+ X509_EXTENSION* ext = get_ext_func(x509Type, extIndex);
+ JNI_TRACE("X509Type_get_ext(%p, %s) => %p", x509Type, oid.c_str(), ext);
+ return ext;
+}
+
+template<typename T, int (*get_ext_by_OBJ_func)(T*, ASN1_OBJECT*, int),
+ X509_EXTENSION* (*get_ext_func)(T*, int)>
+static jbyteArray X509Type_get_ext_oid(JNIEnv* env, T* x509Type, jstring oidString) {
+ X509_EXTENSION* ext = X509Type_get_ext<T, get_ext_by_OBJ_func, get_ext_func>(env, x509Type,
+ oidString);
+ if (ext == NULL) {
+ JNI_TRACE("X509Type_get_ext_oid(%p, %p) => fetching extension failed", x509Type, oidString);
+ return NULL;
+ }
+
+ JNI_TRACE("X509Type_get_ext_oid(%p, %p) => fetching extension failed", x509Type, oidString);
+ return ASN1ToByteArray<ASN1_OCTET_STRING, i2d_ASN1_OCTET_STRING>(env, ext->value);
+}
+
+static jint NativeCrypto_X509_CRL_get_ext(JNIEnv* env, jclass, jlong x509CrlRef, jstring oid) {
+ X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef));
+ JNI_TRACE("X509_CRL_get_ext(%p, %p)", crl, oid);
+ X509_EXTENSION* ext = X509Type_get_ext<X509_CRL, X509_CRL_get_ext_by_OBJ, X509_CRL_get_ext>(
+ env, crl, oid);
+ JNI_TRACE("X509_CRL_get_ext(%p, %p) => %p", crl, oid, ext);
+ return reinterpret_cast<uintptr_t>(ext);
+}
+
+static jint NativeCrypto_X509_REVOKED_get_ext(JNIEnv* env, jclass, jlong x509RevokedRef,
+ jstring oid) {
+ X509_REVOKED* revoked = reinterpret_cast<X509_REVOKED*>(static_cast<uintptr_t>(x509RevokedRef));
+ JNI_TRACE("X509_REVOKED_get_ext(%p, %p)", revoked, oid);
+ X509_EXTENSION* ext = X509Type_get_ext<X509_REVOKED, X509_REVOKED_get_ext_by_OBJ,
+ X509_REVOKED_get_ext>(env, revoked, oid);
+ JNI_TRACE("X509_REVOKED_get_ext(%p, %p) => %p", revoked, oid, ext);
+ return reinterpret_cast<uintptr_t>(ext);
+}
+
+static jlong NativeCrypto_X509_REVOKED_dup(JNIEnv* env, jclass, jlong x509RevokedRef) {
+ X509_REVOKED* revoked = reinterpret_cast<X509_REVOKED*>(static_cast<uintptr_t>(x509RevokedRef));
+ JNI_TRACE("X509_REVOKED_dup(%p)", revoked);
+
+ if (revoked == NULL) {
+ jniThrowNullPointerException(env, "revoked == null");
+ JNI_TRACE("X509_REVOKED_dup(%p) => revoked == null", revoked);
+ return 0;
+ }
+
+ X509_REVOKED* dup = X509_REVOKED_dup(revoked);
+ JNI_TRACE("X509_REVOKED_dup(%p) => %p", revoked, dup);
+ return reinterpret_cast<uintptr_t>(dup);
+}
+
+static jlong NativeCrypto_get_X509_REVOKED_revocationDate(JNIEnv* env, jclass, jlong x509RevokedRef) {
+ X509_REVOKED* revoked = reinterpret_cast<X509_REVOKED*>(static_cast<uintptr_t>(x509RevokedRef));
+ JNI_TRACE("get_X509_REVOKED_revocationDate(%p)", revoked);
+
+ if (revoked == NULL) {
+ jniThrowNullPointerException(env, "revoked == null");
+ JNI_TRACE("get_X509_REVOKED_revocationDate(%p) => revoked == null", revoked);
+ return 0;
+ }
+
+ JNI_TRACE("get_X509_REVOKED_revocationDate(%p) => %p", revoked, revoked->revocationDate);
+ return reinterpret_cast<uintptr_t>(revoked->revocationDate);
+}
+
+static void NativeCrypto_X509_REVOKED_print(JNIEnv* env, jclass, jlong bioRef, jlong x509RevokedRef) {
+ BIO* bio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(bioRef));
+ X509_REVOKED* revoked = reinterpret_cast<X509_REVOKED*>(static_cast<uintptr_t>(x509RevokedRef));
+ JNI_TRACE("X509_REVOKED_print(%p, %p)", bio, revoked);
+
+ if (bio == NULL) {
+ jniThrowNullPointerException(env, "bio == null");
+ JNI_TRACE("X509_REVOKED_print(%p, %p) => bio == null", bio, revoked);
+ return;
+ }
+
+ if (revoked == NULL) {
+ jniThrowNullPointerException(env, "revoked == null");
+ JNI_TRACE("X509_REVOKED_print(%p, %p) => revoked == null", bio, revoked);
+ return;
+ }
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wwrite-strings"
+ BIO_printf(bio, "Serial Number: ");
+ i2a_ASN1_INTEGER(bio, revoked->serialNumber);
+ BIO_printf(bio, "\nRevocation Date: ");
+ ASN1_TIME_print(bio, revoked->revocationDate);
+ BIO_printf(bio, "\n");
+ X509V3_extensions_print(bio, "CRL entry extensions", revoked->extensions, 0, 0);
+#pragma GCC diagnostic pop
+}
+
+static jbyteArray NativeCrypto_get_X509_CRL_crl_enc(JNIEnv* env, jclass, jlong x509CrlRef) {
+ X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef));
+ JNI_TRACE("get_X509_CRL_crl_enc(%p)", crl);
+ return ASN1ToByteArray<X509_CRL_INFO, i2d_X509_CRL_INFO>(env, crl->crl);
+}
+
+static void NativeCrypto_X509_CRL_verify(JNIEnv* env, jclass, jlong x509CrlRef, jlong pkeyRef) {
+ X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef));
+ EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
+ JNI_TRACE("X509_CRL_verify(%p, %p)", crl, pkey);
+
+ if (crl == NULL) {
+ jniThrowNullPointerException(env, "crl == null");
+ JNI_TRACE("X509_CRL_verify(%p, %p) => crl == null", crl, pkey);
+ return;
+ }
+
+ if (pkey == NULL) {
+ jniThrowNullPointerException(env, "pkey == null");
+ JNI_TRACE("X509_CRL_verify(%p, %p) => pkey == null", crl, pkey);
+ return;
+ }
+
+ if (X509_CRL_verify(crl, pkey) != 1) {
+ throwExceptionIfNecessary(env, "X509_CRL_verify");
+ JNI_TRACE("X509_CRL_verify(%p, %p) => verify failure", crl, pkey);
+ } else {
+ JNI_TRACE("X509_CRL_verify(%p, %p) => verify success", crl, pkey);
+ }
+}
+
+static jlong NativeCrypto_X509_CRL_get_lastUpdate(JNIEnv* env, jclass, jlong x509CrlRef) {
+ X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef));
+ JNI_TRACE("X509_CRL_get_lastUpdate(%p)", crl);
+
+ if (crl == NULL) {
+ jniThrowNullPointerException(env, "crl == null");
+ JNI_TRACE("X509_CRL_get_lastUpdate(%p) => crl == null", crl);
+ return 0;
+ }
+
+ ASN1_TIME* lastUpdate = X509_CRL_get_lastUpdate(crl);
+ JNI_TRACE("X509_CRL_get_lastUpdate(%p) => %p", crl, lastUpdate);
+ return reinterpret_cast<uintptr_t>(lastUpdate);
+}
+
+static jlong NativeCrypto_X509_CRL_get_nextUpdate(JNIEnv* env, jclass, jlong x509CrlRef) {
+ X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef));
+ JNI_TRACE("X509_CRL_get_nextUpdate(%p)", crl);
+
+ if (crl == NULL) {
+ jniThrowNullPointerException(env, "crl == null");
+ JNI_TRACE("X509_CRL_get_nextUpdate(%p) => crl == null", crl);
+ return 0;
+ }
+
+ ASN1_TIME* nextUpdate = X509_CRL_get_nextUpdate(crl);
+ JNI_TRACE("X509_CRL_get_nextUpdate(%p) => %p", crl, nextUpdate);
+ return reinterpret_cast<uintptr_t>(nextUpdate);
+}
+
+static jbyteArray NativeCrypto_i2d_X509_REVOKED(JNIEnv* env, jclass, jlong x509RevokedRef) {
+ X509_REVOKED* x509Revoked =
+ reinterpret_cast<X509_REVOKED*>(static_cast<uintptr_t>(x509RevokedRef));
+ JNI_TRACE("i2d_X509_REVOKED(%p)", x509Revoked);
+ return ASN1ToByteArray<X509_REVOKED, i2d_X509_REVOKED>(env, x509Revoked);
+}
+
+static jint NativeCrypto_X509_supported_extension(JNIEnv* env, jclass, jlong x509ExtensionRef) {
+ X509_EXTENSION* ext = reinterpret_cast<X509_EXTENSION*>(static_cast<uintptr_t>(x509ExtensionRef));
+
+ if (ext == NULL) {
+ jniThrowNullPointerException(env, "ext == NULL");
+ return 0;
+ }
+
+ return X509_supported_extension(ext);
+}
+
+static inline void get_ASN1_TIME_data(char **data, int* output, size_t len) {
+ char c = **data;
+ **data = '\0';
+ *data -= len;
+ *output = atoi(*data);
+ *(*data + len) = c;
+}
+
+static void NativeCrypto_ASN1_TIME_to_Calendar(JNIEnv* env, jclass, jlong asn1TimeRef, jobject calendar) {
+ ASN1_TIME* asn1Time = reinterpret_cast<ASN1_TIME*>(static_cast<uintptr_t>(asn1TimeRef));
+ JNI_TRACE("ASN1_TIME_to_Calendar(%p, %p)", asn1Time, calendar);
+
+ if (asn1Time == NULL) {
+ jniThrowNullPointerException(env, "asn1Time == null");
+ return;
+ }
+
+ Unique_ASN1_GENERALIZEDTIME gen(ASN1_TIME_to_generalizedtime(asn1Time, NULL));
+ if (gen.get() == NULL) {
+ jniThrowNullPointerException(env, "asn1Time == null");
+ return;
+ }
+
+ if (gen->length < 14 || gen->data == NULL) {
+ jniThrowNullPointerException(env, "gen->length < 14 || gen->data == NULL");
+ return;
+ }
+
+ int sec, min, hour, mday, mon, year;
+
+ char *p = (char*) &gen->data[14];
+
+ get_ASN1_TIME_data(&p, &sec, 2);
+ get_ASN1_TIME_data(&p, &min, 2);
+ get_ASN1_TIME_data(&p, &hour, 2);
+ get_ASN1_TIME_data(&p, &mday, 2);
+ get_ASN1_TIME_data(&p, &mon, 2);
+ get_ASN1_TIME_data(&p, &year, 4);
+
+ env->CallVoidMethod(calendar, calendar_setMethod, year, mon - 1, mday, hour, min, sec);
+}
+
+static jstring NativeCrypto_OBJ_txt2nid_oid(JNIEnv* env, jclass, jstring oidStr) {
+ JNI_TRACE("OBJ_txt2nid_oid(%p)", oidStr);
+
+ ScopedUtfChars oid(env, oidStr);
+ if (oid.c_str() == NULL) {
+ return NULL;
+ }
+
+ JNI_TRACE("OBJ_txt2nid_oid(%s)", oid.c_str());
+
+ int nid = OBJ_txt2nid(oid.c_str());
+ if (nid == NID_undef) {
+ JNI_TRACE("OBJ_txt2nid_oid(%s) => NID_undef", oid.c_str());
+ freeOpenSslErrorState();
+ return NULL;
+ }
+
+ Unique_ASN1_OBJECT obj(OBJ_nid2obj(nid));
+ if (obj.get() == NULL) {
+ throwExceptionIfNecessary(env, "OBJ_nid2obj");
+ return NULL;
+ }
+
+ ScopedLocalRef<jstring> ouputStr(env, ASN1_OBJECT_to_OID_string(env, obj.get()));
+ JNI_TRACE("OBJ_txt2nid_oid(%s) => %p", oid.c_str(), ouputStr.get());
+ return ouputStr.release();
+}
+
+static jstring NativeCrypto_X509_NAME_print_ex(JNIEnv* env, jclass, jlong x509NameRef, jlong jflags) {
+ X509_NAME* x509name = reinterpret_cast<X509_NAME*>(static_cast<uintptr_t>(x509NameRef));
+ unsigned long flags = static_cast<unsigned long>(jflags);
+ JNI_TRACE("X509_NAME_print_ex(%p, %ld)", x509name, flags);
+
+ if (x509name == NULL) {
+ jniThrowNullPointerException(env, "x509name == null");
+ JNI_TRACE("X509_NAME_print_ex(%p, %ld) => x509name == null", x509name, flags);
+ return NULL;
+ }
+
+ return X509_NAME_to_jstring(env, x509name, flags);
+}
+
+template <typename T, T* (*d2i_func)(BIO*, T**)>
+static jlong d2i_ASN1Object_to_jlong(JNIEnv* env, jlong bioRef) {
+ BIO* bio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(bioRef));
+ JNI_TRACE("d2i_ASN1Object_to_jlong(%p)", bio);
+
+ if (bio == NULL) {
+ jniThrowNullPointerException(env, "bio == null");
+ return 0;
+ }
+
+ T* x = d2i_func(bio, NULL);
+ if (x == NULL) {
+ throwExceptionIfNecessary(env, "d2i_ASN1Object_to_jlong");
+ return 0;
+ }
+
+ return reinterpret_cast<uintptr_t>(x);
+}
+
+static jlong NativeCrypto_d2i_X509_CRL_bio(JNIEnv* env, jclass, jlong bioRef) {
+ return d2i_ASN1Object_to_jlong<X509_CRL, d2i_X509_CRL_bio>(env, bioRef);
+}
+
+static jlong NativeCrypto_d2i_X509_bio(JNIEnv* env, jclass, jlong bioRef) {
+ return d2i_ASN1Object_to_jlong<X509, d2i_X509_bio>(env, bioRef);
+}
+
+static jbyteArray NativeCrypto_i2d_X509(JNIEnv* env, jclass, jlong x509Ref) {
+ X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
+ JNI_TRACE("i2d_X509(%p)", x509);
+ return ASN1ToByteArray<X509, i2d_X509>(env, x509);
+}
+
+template<typename T, T* (*PEM_read_func)(BIO*, T**, pem_password_cb*, void*)>
+static jlong PEM_ASN1Object_to_jlong(JNIEnv* env, jlong bioRef) {
+ BIO* bio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(bioRef));
+ JNI_TRACE("PEM_ASN1Object_to_jlong(%p)", bio);
+
+ if (bio == NULL) {
+ jniThrowNullPointerException(env, "bio == null");
+ JNI_TRACE("PEM_ASN1Object_to_jlong(%p) => bio == null", bio);
+ return 0;
+ }
+
+ T* x = PEM_read_func(bio, NULL, NULL, NULL);
+ if (x == NULL) {
+ throwExceptionIfNecessary(env, "PEM_ASN1Object_to_jlong");
+ JNI_TRACE("PEM_ASN1Object_to_jlong(%p) => threw exception", bio);
+ return 0;
+ }
+
+ JNI_TRACE("PEM_ASN1Object_to_jlong(%p) => %p", bio, x);
+ return reinterpret_cast<uintptr_t>(x);
+}
+
+static jlong NativeCrypto_PEM_read_bio_X509(JNIEnv* env, jclass, jlong bioRef) {
+ JNI_TRACE("PEM_read_bio_X509(0x%llx)", bioRef);
+ return PEM_ASN1Object_to_jlong<X509, PEM_read_bio_X509>(env, bioRef);
+}
+
+static jlong NativeCrypto_PEM_read_bio_X509_CRL(JNIEnv* env, jclass, jlong bioRef) {
+ JNI_TRACE("PEM_read_bio_X509_CRL(0x%llx)", bioRef);
+ return PEM_ASN1Object_to_jlong<X509_CRL, PEM_read_bio_X509_CRL>(env, bioRef);
+}
+
+static STACK_OF(X509)* PKCS7_get_certs(PKCS7* pkcs7) {
+ if (PKCS7_type_is_signed(pkcs7)) {
+ return pkcs7->d.sign->cert;
+ } else if (PKCS7_type_is_signedAndEnveloped(pkcs7)) {
+ return pkcs7->d.signed_and_enveloped->cert;
+ } else {
+ JNI_TRACE("PKCS7_get_certs(%p) => unknown PKCS7 type", pkcs7);
+ return NULL;
+ }
+}
+
+static STACK_OF(X509_CRL)* PKCS7_get_CRLs(PKCS7* pkcs7) {
+ if (PKCS7_type_is_signed(pkcs7)) {
+ return pkcs7->d.sign->crl;
+ } else if (PKCS7_type_is_signedAndEnveloped(pkcs7)) {
+ return pkcs7->d.signed_and_enveloped->crl;
+ } else {
+ JNI_TRACE("PKCS7_get_CRLs(%p) => unknown PKCS7 type", pkcs7);
+ return NULL;
+ }
+}
+
+template <typename T, typename T_stack>
+static jlongArray PKCS7_to_ItemArray(JNIEnv* env, T_stack* stack, T* (*dup_func)(T*))
+{
+ if (stack == NULL) {
+ return NULL;
+ }
+
+ ScopedLocalRef<jlongArray> ref_array(env, NULL);
+ size_t size = sk_num(reinterpret_cast<_STACK*>(stack));
+ ref_array.reset(env->NewLongArray(size));
+ ScopedLongArrayRW items(env, ref_array.get());
+ for (size_t i = 0; i < size; i++) {
+ T* item = reinterpret_cast<T*>(sk_value(reinterpret_cast<_STACK*>(stack), i));
+ items[i] = reinterpret_cast<uintptr_t>(dup_func(item));
+ }
+
+ JNI_TRACE("PKCS7_to_ItemArray(%p) => %p [size=%d]", stack, ref_array.get(), size);
+ return ref_array.release();
+}
+
+#define PKCS7_CERTS 1
+#define PKCS7_CRLS 2
+
+static jlongArray NativeCrypto_PEM_read_bio_PKCS7(JNIEnv* env, jclass, jlong bioRef, jint which) {
+ BIO* bio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(bioRef));
+ JNI_TRACE("PEM_read_bio_PKCS7_CRLs(%p)", bio);
+
+ if (bio == NULL) {
+ jniThrowNullPointerException(env, "bio == null");
+ JNI_TRACE("PEM_read_bio_PKCS7_CRLs(%p) => bio == null", bio);
+ return 0;
+ }
+
+ Unique_PKCS7 pkcs7(PEM_read_bio_PKCS7(bio, NULL, NULL, NULL));
+ if (pkcs7.get() == NULL) {
+ throwExceptionIfNecessary(env, "PEM_read_bio_PKCS7_CRLs");
+ JNI_TRACE("PEM_read_bio_PKCS7_CRLs(%p) => threw exception", bio);
+ return 0;
+ }
+
+ switch (which) {
+ case PKCS7_CERTS:
+ return PKCS7_to_ItemArray<X509, STACK_OF(X509)>(env, PKCS7_get_certs(pkcs7.get()), X509_dup);
+ case PKCS7_CRLS:
+ return PKCS7_to_ItemArray<X509_CRL, STACK_OF(X509_CRL)>(env, PKCS7_get_CRLs(pkcs7.get()),
+ X509_CRL_dup);
+ default:
+ jniThrowRuntimeException(env, "unknown PKCS7 field");
+ return NULL;
+ }
+}
+
+static jlongArray NativeCrypto_d2i_PKCS7_bio(JNIEnv* env, jclass, jlong bioRef, jint which) {
+ BIO* bio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(bioRef));
+ JNI_TRACE("d2i_PKCS7_bio_certs(%p)", bio);
+
+ if (bio == NULL) {
+ jniThrowNullPointerException(env, "bio == null");
+ JNI_TRACE("d2i_PKCS7_bio_certs(%p) => bio == null", bio);
+ return 0;
+ }
+
+ Unique_PKCS7 pkcs7(d2i_PKCS7_bio(bio, NULL));
+ if (pkcs7.get() == NULL) {
+ throwExceptionIfNecessary(env, "d2i_PKCS7_bio_certs");
+ JNI_TRACE("d2i_PKCS7_bio_certs(%p) => threw exception", bio);
+ return 0;
+ }
+
+ switch (which) {
+ case PKCS7_CERTS:
+ return PKCS7_to_ItemArray<X509, STACK_OF(X509)>(env, PKCS7_get_certs(pkcs7.get()), X509_dup);
+ case PKCS7_CRLS:
+ return PKCS7_to_ItemArray<X509_CRL, STACK_OF(X509_CRL)>(env, PKCS7_get_CRLs(pkcs7.get()),
+ X509_CRL_dup);
+ default:
+ jniThrowRuntimeException(env, "unknown PKCS7 field");
+ return NULL;
+ }}
+
+static void NativeCrypto_X509_free(JNIEnv* env, jclass, jlong x509Ref) {
+ X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
+ JNI_TRACE("X509_free(%p)", x509);
+
+ if (x509 == NULL) {
+ jniThrowNullPointerException(env, "x509 == null");
+ JNI_TRACE("X509_free(%p) => x509 == null", x509);
+ return;
+ }
+
+ X509_free(x509);
+}
+
+static jint NativeCrypto_X509_cmp(JNIEnv* env, jclass, jlong x509Ref1, jlong x509Ref2) {
+ X509* x509_1 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref1));
+ X509* x509_2 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref2));
+ JNI_TRACE("X509_cmp(%p, %p)", x509_1, x509_2);
+
+ if (x509_1 == NULL) {
+ jniThrowNullPointerException(env, "x509_1 == null");
+ JNI_TRACE("X509_cmp(%p, %p) => x509_1 == null", x509_1, x509_2);
+ return -1;
+ }
+
+ if (x509_2 == NULL) {
+ jniThrowNullPointerException(env, "x509_2 == null");
+ JNI_TRACE("X509_cmp(%p, %p) => x509_2 == null", x509_1, x509_2);
+ return -1;
+ }
+
+ int ret = X509_cmp(x509_1, x509_2);
+ JNI_TRACE("X509_cmp(%p, %p) => %d", x509_1, x509_2, ret);
+ return ret;
+}
+
+static jint NativeCrypto_get_X509_hashCode(JNIEnv* env, jclass, jlong x509Ref) {
+ X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
+
+ if (x509 == NULL) {
+ jniThrowNullPointerException(env, "x509 == null");
+ JNI_TRACE("get_X509_hashCode(%p) => x509 == null", x509);
+ return 0;
+ }
+
+ // Force caching extensions.
+ X509_check_ca(x509);
+
+ jint hashCode = 0L;
+ for (int i = 0; i < SHA_DIGEST_LENGTH; i++) {
+ hashCode = 31 * hashCode + x509->sha1_hash[i];
+ }
+ return hashCode;
+}
+
+static void NativeCrypto_X509_print_ex(JNIEnv* env, jclass, jlong bioRef, jlong x509Ref,
+ jlong nmflagJava, jlong certflagJava) {
+ BIO* bio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(bioRef));
+ X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
+ long nmflag = static_cast<long>(nmflagJava);
+ long certflag = static_cast<long>(certflagJava);
+ JNI_TRACE("X509_print_ex(%p, %p, %ld, %ld)", bio, x509, nmflag, certflag);
+
+ if (bio == NULL) {
+ jniThrowNullPointerException(env, "bio == null");
+ JNI_TRACE("X509_print_ex(%p, %p, %ld, %ld) => bio == null", bio, x509, nmflag, certflag);
+ return;
+ }
+
+ if (x509 == NULL) {
+ jniThrowNullPointerException(env, "x509 == null");
+ JNI_TRACE("X509_print_ex(%p, %p, %ld, %ld) => x509 == null", bio, x509, nmflag, certflag);
+ return;
+ }
+
+ X509_print_ex(bio, x509, nmflag, certflag);
+ JNI_TRACE("X509_print_ex(%p, %p, %ld, %ld) => success", bio, x509, nmflag, certflag);
+}
+
+static jlong NativeCrypto_X509_get_pubkey(JNIEnv* env, jclass, jlong x509Ref) {
+ X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
+ JNI_TRACE("X509_get_pubkey(%p)", x509);
+
+ if (x509 == NULL) {
+ jniThrowNullPointerException(env, "x509 == null");
+ JNI_TRACE("X509_get_pubkey(%p) => x509 == null", x509);
+ return 0;
+ }
+
+ Unique_EVP_PKEY pkey(X509_get_pubkey(x509));
+ if (pkey.get() == NULL) {
+ throwExceptionIfNecessary(env, "X509_get_pubkey");
+ return 0;
+ }
+
+ return reinterpret_cast<uintptr_t>(pkey.release());
+}
+
+static jbyteArray NativeCrypto_X509_get_issuer_name(JNIEnv* env, jclass, jlong x509Ref) {
+ X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
+ JNI_TRACE("X509_get_issuer_name(%p)", x509);
+ return ASN1ToByteArray<X509_NAME, i2d_X509_NAME>(env, X509_get_issuer_name(x509));
+}
+
+static jbyteArray NativeCrypto_X509_get_subject_name(JNIEnv* env, jclass, jlong x509Ref) {
+ X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
+ JNI_TRACE("X509_get_subject_name(%p)", x509);
+ return ASN1ToByteArray<X509_NAME, i2d_X509_NAME>(env, X509_get_subject_name(x509));
+}
+
+static jstring NativeCrypto_get_X509_pubkey_oid(JNIEnv* env, jclass, jlong x509Ref) {
+ X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
+ JNI_TRACE("get_X509_pubkey_oid(%p)", x509);
+
+ if (x509 == NULL) {
+ jniThrowNullPointerException(env, "x509 == null");
+ JNI_TRACE("get_X509_pubkey_oid(%p) => x509 == null", x509);
+ return NULL;
+ }
+
+ X509_PUBKEY* pubkey = X509_get_X509_PUBKEY(x509);
+ return ASN1_OBJECT_to_OID_string(env, pubkey->algor->algorithm);
+}
+
+static jstring NativeCrypto_get_X509_sig_alg_oid(JNIEnv* env, jclass, jlong x509Ref) {
+ X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
+ JNI_TRACE("get_X509_sig_alg_oid(%p)", x509);
+
+ if (x509 == NULL || x509->sig_alg == NULL) {
+ jniThrowNullPointerException(env, "x509 == NULL || x509->sig_alg == NULL");
+ JNI_TRACE("get_X509_sig_alg_oid(%p) => x509 == NULL", x509);
+ return NULL;
+ }
+
+ return ASN1_OBJECT_to_OID_string(env, x509->sig_alg->algorithm);
+}
+
+static jbyteArray NativeCrypto_get_X509_sig_alg_parameter(JNIEnv* env, jclass, jlong x509Ref) {
+ X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
+ JNI_TRACE("get_X509_sig_alg_parameter(%p)", x509);
+
+ if (x509 == NULL) {
+ jniThrowNullPointerException(env, "x509 == null");
+ JNI_TRACE("get_X509_sig_alg_parameter(%p) => x509 == null", x509);
+ return NULL;
+ }
+
+ if (x509->sig_alg->parameter == NULL) {
+ JNI_TRACE("get_X509_sig_alg_parameter(%p) => null", x509);
+ return NULL;
+ }
+
+ return ASN1ToByteArray<ASN1_TYPE, i2d_ASN1_TYPE>(env, x509->sig_alg->parameter);
+}
+
+static jbooleanArray NativeCrypto_get_X509_issuerUID(JNIEnv* env, jclass, jlong x509Ref) {
+ X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
+ JNI_TRACE("get_X509_issuerUID(%p)", x509);
+
+ if (x509 == NULL) {
+ jniThrowNullPointerException(env, "x509 == null");
+ JNI_TRACE("get_X509_issuerUID(%p) => x509 == null", x509);
+ return NULL;
+ }
+
+ if (x509->cert_info->issuerUID == NULL) {
+ JNI_TRACE("get_X509_issuerUID(%p) => null", x509);
+ return NULL;
+ }
+
+ return ASN1BitStringToBooleanArray(env, x509->cert_info->issuerUID);
+}
+static jbooleanArray NativeCrypto_get_X509_subjectUID(JNIEnv* env, jclass, jlong x509Ref) {
+ X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
+ JNI_TRACE("get_X509_subjectUID(%p)", x509);
+
+ if (x509 == NULL) {
+ jniThrowNullPointerException(env, "x509 == null");
+ JNI_TRACE("get_X509_subjectUID(%p) => x509 == null", x509);
+ return NULL;
+ }
+
+ if (x509->cert_info->subjectUID == NULL) {
+ JNI_TRACE("get_X509_subjectUID(%p) => null", x509);
+ return NULL;
+ }
+
+ return ASN1BitStringToBooleanArray(env, x509->cert_info->subjectUID);
+}
+
+static jbooleanArray NativeCrypto_get_X509_ex_kusage(JNIEnv* env, jclass, jlong x509Ref) {
+ X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
+ JNI_TRACE("get_X509_ex_kusage(%p)", x509);
+
+ if (x509 == NULL) {
+ jniThrowNullPointerException(env, "x509 == null");
+ JNI_TRACE("get_X509_ex_kusage(%p) => x509 == null", x509);
+ return NULL;
+ }
+
+ Unique_ASN1_BIT_STRING bitStr(static_cast<ASN1_BIT_STRING*>(
+ X509_get_ext_d2i(x509, NID_key_usage, NULL, NULL)));
+ if (bitStr.get() == NULL) {
+ JNI_TRACE("get_X509_ex_kusage(%p) => conversion to bitstring failed", x509);
+ return NULL;
+ }
+
+ return ASN1BitStringToBooleanArray(env, bitStr.get());
+}
+
+static jobjectArray NativeCrypto_get_X509_ex_xkusage(JNIEnv* env, jclass, jlong x509Ref) {
+ X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
+ JNI_TRACE("get_X509_ex_xkusage(%p)", x509);
+
+ if (x509 == NULL) {
+ jniThrowNullPointerException(env, "x509 == null");
+ JNI_TRACE("get_X509_ex_xkusage(%p) => x509 == null", x509);
+ return NULL;
+ }
+
+ Unique_sk_ASN1_OBJECT objArray(static_cast<STACK_OF(ASN1_OBJECT)*>(
+ X509_get_ext_d2i(x509, NID_ext_key_usage, NULL, NULL)));
+ if (objArray.get() == NULL) {
+ JNI_TRACE("get_X509_ex_xkusage(%p) => null", x509);
+ return NULL;
+ }
+
+ size_t size = sk_ASN1_OBJECT_num(objArray.get());
+ ScopedLocalRef<jobjectArray> exKeyUsage(env, env->NewObjectArray(size,
+ JniConstants::stringClass, NULL));
+ if (exKeyUsage.get() == NULL) {
+ return NULL;
+ }
+
+ for (size_t i = 0; i < size; i++) {
+ ScopedLocalRef<jstring> oidStr(env, ASN1_OBJECT_to_OID_string(env,
+ sk_ASN1_OBJECT_value(objArray.get(), i)));
+ env->SetObjectArrayElement(exKeyUsage.get(), i, oidStr.get());
+ }
+
+ JNI_TRACE("get_X509_ex_xkusage(%p) => success (%d entries)", x509, size);
+ return exKeyUsage.release();
+}
+
+static jint NativeCrypto_X509_check_ca(JNIEnv* env, jclass, jlong x509Ref) {
+ X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
+ JNI_TRACE("X509_check_ca(%p)", x509);
+
+ if (x509 == NULL) {
+ jniThrowNullPointerException(env, "x509 == null");
+ JNI_TRACE("X509_check_ca(%p) => x509 == null", x509);
+ return 0;
+ }
+
+ int ret = X509_check_ca(x509);
+ JNI_TRACE("X509_check_ca(%p) => %d", x509, ret);
+ return ret;
+}
+
+static jint NativeCrypto_get_X509_ex_pathlen(JNIEnv* env, jclass, jlong x509Ref) {
+ X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
+ JNI_TRACE("get_X509_ex_pathlen(%p)", x509);
+
+ if (x509 == NULL) {
+ jniThrowNullPointerException(env, "x509 == null");
+ JNI_TRACE("get_X509_ex_pathlen(%p) => x509 == null", x509);
+ return 0;
+ }
+
+ /* Just need to do this to cache the ex_* values. */
+ X509_check_ca(x509);
+
+ JNI_TRACE("get_X509_ex_pathlen(%p) => %ld", x509, x509->ex_pathlen);
+ return x509->ex_pathlen;
+}
+
+static jbyteArray NativeCrypto_X509_get_ext_oid(JNIEnv* env, jclass, jlong x509Ref,
+ jstring oidString) {
+ X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref));
+ JNI_TRACE("X509_get_ext_oid(%p, %p)", x509, oidString);
+ return X509Type_get_ext_oid<X509, X509_get_ext_by_OBJ, X509_get_ext>(env, x509, oidString);
+}
+
+static jbyteArray NativeCrypto_X509_CRL_get_ext_oid(JNIEnv* env, jclass, jlong x509CrlRef,
+ jstring oidString) {
+ X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef));
+ JNI_TRACE("X509_CRL_get_ext_oid(%p, %p)", crl, oidString);
+ return X509Type_get_ext_oid<X509_CRL, X509_CRL_get_ext_by_OBJ, X509_CRL_get_ext>(env, crl,
+ oidString);
+}
+
+static jbyteArray NativeCrypto_X509_REVOKED_get_ext_oid(JNIEnv* env, jclass, jlong x509RevokedRef,
+ jstring oidString) {
+ X509_REVOKED* revoked = reinterpret_cast<X509_REVOKED*>(static_cast<uintptr_t>(x509RevokedRef));
+ JNI_TRACE("X509_REVOKED_get_ext_oid(%p, %p)", revoked, oidString);
+ return X509Type_get_ext_oid<X509_REVOKED, X509_REVOKED_get_ext_by_OBJ, X509_REVOKED_get_ext>(
+ env, revoked, oidString);
+}
+
+template<typename T, int (*get_ext_by_critical_func)(T*, int, int), X509_EXTENSION* (*get_ext_func)(T*, int)>
+static jobjectArray get_X509Type_ext_oids(JNIEnv* env, jlong x509Ref, jint critical) {
+ T* x509 = reinterpret_cast<T*>(static_cast<uintptr_t>(x509Ref));
+ JNI_TRACE("get_X509Type_ext_oids(%p, %d)", x509, critical);
+
+ if (x509 == NULL) {
+ jniThrowNullPointerException(env, "x509 == null");
+ JNI_TRACE("get_X509Type_ext_oids(%p, %d) => x509 == null", x509, critical);
+ return NULL;
+ }
+
+ int lastPos = -1;
+ int count = 0;
+ while ((lastPos = get_ext_by_critical_func(x509, critical, lastPos)) != -1) {
+ count++;
+ }
+
+ JNI_TRACE("get_X509Type_ext_oids(%p, %d) has %d entries", x509, critical, count);
+
+ ScopedLocalRef<jobjectArray> joa(env, env->NewObjectArray(count, JniConstants::stringClass, NULL));
+ if (joa.get() == NULL) {
+ JNI_TRACE("get_X509Type_ext_oids(%p, %d) => fail to allocate result array", x509, critical);
+ return NULL;
+ }
+
+ lastPos = -1;
+ count = 0;
+ while ((lastPos = get_ext_by_critical_func(x509, critical, lastPos)) != -1) {
+ X509_EXTENSION* ext = get_ext_func(x509, lastPos);
+
+ ScopedLocalRef<jstring> extOid(env, ASN1_OBJECT_to_OID_string(env, ext->object));
+ if (extOid.get() == NULL) {
+ JNI_TRACE("get_X509Type_ext_oids(%p) => couldn't get OID", x509);
+ return NULL;
+ }
+
+ env->SetObjectArrayElement(joa.get(), count++, extOid.get());
+ }
+
+ JNI_TRACE("get_X509Type_ext_oids(%p, %d) => success", x509, critical);
+ return joa.release();
+}
+
+static jobjectArray NativeCrypto_get_X509_ext_oids(JNIEnv* env, jclass, jlong x509Ref,
+ jint critical) {
+ JNI_TRACE("get_X509_ext_oids(0x%llx, %d)", x509Ref, critical);
+ return get_X509Type_ext_oids<X509, X509_get_ext_by_critical, X509_get_ext>(env, x509Ref,
+ critical);
+}
+
+static jobjectArray NativeCrypto_get_X509_CRL_ext_oids(JNIEnv* env, jclass, jlong x509CrlRef,
+ jint critical) {
+ JNI_TRACE("get_X509_CRL_ext_oids(0x%llx, %d)", x509CrlRef, critical);
+ return get_X509Type_ext_oids<X509_CRL, X509_CRL_get_ext_by_critical, X509_CRL_get_ext>(env,
+ x509CrlRef, critical);
+}
+
+static jobjectArray NativeCrypto_get_X509_REVOKED_ext_oids(JNIEnv* env, jclass, jlong x509RevokedRef,
+ jint critical) {
+ JNI_TRACE("get_X509_CRL_ext_oids(0x%llx, %d)", x509RevokedRef, critical);
+ return get_X509Type_ext_oids<X509_REVOKED, X509_REVOKED_get_ext_by_critical,
+ X509_REVOKED_get_ext>(env, x509RevokedRef, critical);
+}
+
#ifdef WITH_JNI_TRACE
/**
* Based on example logging call back from SSL_CTX_set_info_callback man page
@@ -3638,7 +5067,7 @@
for (int i = 0; i < count; i++) {
X509* cert = sk_X509_value(chain, i);
- ScopedLocalRef<jbyteArray> byteArray(env, ASN1ToByteArray<X509>(env, cert, i2d_X509));
+ ScopedLocalRef<jbyteArray> byteArray(env, ASN1ToByteArray<X509, i2d_X509>(env, cert));
if (byteArray.get() == NULL) {
return NULL;
}
@@ -3671,8 +5100,8 @@
for (int i = 0; i < count; i++) {
X509_NAME* principal = sk_X509_NAME_value(names, i);
- ScopedLocalRef<jbyteArray> byteArray(env, ASN1ToByteArray<X509_NAME>(env, principal,
- i2d_X509_NAME));
+ ScopedLocalRef<jbyteArray> byteArray(env, ASN1ToByteArray<X509_NAME, i2d_X509_NAME>(env,
+ principal));
if (byteArray.get() == NULL) {
return NULL;
}
@@ -6019,11 +7448,7 @@
static jbyteArray NativeCrypto_i2d_SSL_SESSION(JNIEnv* env, jclass, jlong ssl_session_address) {
SSL_SESSION* ssl_session = to_SSL_SESSION(env, ssl_session_address, true);
JNI_TRACE("ssl_session=%p NativeCrypto_i2d_SSL_SESSION", ssl_session);
- if (ssl_session == NULL) {
- return NULL;
- }
-
- return ASN1ToByteArray<SSL_SESSION>(env, ssl_session, i2d_SSL_SESSION);
+ return ASN1ToByteArray<SSL_SESSION, i2d_SSL_SESSION>(env, ssl_session);
}
/**
@@ -6168,6 +7593,69 @@
NATIVE_METHOD(NativeCrypto, BIO_read, "(J[B)I"),
NATIVE_METHOD(NativeCrypto, BIO_write, "(J[BII)V"),
NATIVE_METHOD(NativeCrypto, BIO_free, "(J)V"),
+ NATIVE_METHOD(NativeCrypto, X509_NAME_print_ex, "(JJ)Ljava/lang/String;"),
+ NATIVE_METHOD(NativeCrypto, d2i_X509_bio, "(J)J"),
+ NATIVE_METHOD(NativeCrypto, i2d_X509, "(J)[B"),
+ NATIVE_METHOD(NativeCrypto, PEM_read_bio_X509, "(J)J"),
+ NATIVE_METHOD(NativeCrypto, PEM_read_bio_PKCS7, "(JI)[J"),
+ NATIVE_METHOD(NativeCrypto, d2i_PKCS7_bio, "(JI)[J"),
+ NATIVE_METHOD(NativeCrypto, X509_free, "(J)V"),
+ NATIVE_METHOD(NativeCrypto, X509_cmp, "(JJ)I"),
+ NATIVE_METHOD(NativeCrypto, get_X509_hashCode, "(J)I"),
+ NATIVE_METHOD(NativeCrypto, X509_print_ex, "(JJJJ)V"),
+ NATIVE_METHOD(NativeCrypto, X509_get_pubkey, "(J)J"),
+ NATIVE_METHOD(NativeCrypto, X509_get_issuer_name, "(J)[B"),
+ NATIVE_METHOD(NativeCrypto, X509_get_subject_name, "(J)[B"),
+ NATIVE_METHOD(NativeCrypto, get_X509_pubkey_oid, "(J)Ljava/lang/String;"),
+ NATIVE_METHOD(NativeCrypto, get_X509_sig_alg_oid, "(J)Ljava/lang/String;"),
+ NATIVE_METHOD(NativeCrypto, get_X509_sig_alg_parameter, "(J)[B"),
+ NATIVE_METHOD(NativeCrypto, get_X509_issuerUID, "(J)[Z"),
+ NATIVE_METHOD(NativeCrypto, get_X509_subjectUID, "(J)[Z"),
+ NATIVE_METHOD(NativeCrypto, get_X509_ex_kusage, "(J)[Z"),
+ NATIVE_METHOD(NativeCrypto, get_X509_ex_xkusage, "(J)[Ljava/lang/String;"),
+ NATIVE_METHOD(NativeCrypto, X509_check_ca, "(J)I"),
+ NATIVE_METHOD(NativeCrypto, get_X509_ex_pathlen, "(J)I"),
+ NATIVE_METHOD(NativeCrypto, X509_get_ext_oid, "(JLjava/lang/String;)[B"),
+ NATIVE_METHOD(NativeCrypto, X509_CRL_get_ext_oid, "(JLjava/lang/String;)[B"),
+ NATIVE_METHOD(NativeCrypto, get_X509_CRL_crl_enc, "(J)[B"),
+ NATIVE_METHOD(NativeCrypto, X509_CRL_verify, "(JJ)V"),
+ NATIVE_METHOD(NativeCrypto, X509_CRL_get_lastUpdate, "(J)J"),
+ NATIVE_METHOD(NativeCrypto, X509_CRL_get_nextUpdate, "(J)J"),
+ NATIVE_METHOD(NativeCrypto, X509_REVOKED_get_ext_oid, "(JLjava/lang/String;)[B"),
+ NATIVE_METHOD(NativeCrypto, X509_REVOKED_get_serialNumber, "(J)[B"),
+ NATIVE_METHOD(NativeCrypto, X509_REVOKED_print, "(JJ)V"),
+ NATIVE_METHOD(NativeCrypto, get_X509_REVOKED_revocationDate, "(J)J"),
+ NATIVE_METHOD(NativeCrypto, get_X509_ext_oids, "(JI)[Ljava/lang/String;"),
+ NATIVE_METHOD(NativeCrypto, get_X509_CRL_ext_oids, "(JI)[Ljava/lang/String;"),
+ NATIVE_METHOD(NativeCrypto, get_X509_REVOKED_ext_oids, "(JI)[Ljava/lang/String;"),
+ NATIVE_METHOD(NativeCrypto, get_X509_GENERAL_NAME_stack, "(JI)[[Ljava/lang/Object;"),
+ NATIVE_METHOD(NativeCrypto, X509_get_notBefore, "(J)J"),
+ NATIVE_METHOD(NativeCrypto, X509_get_notAfter, "(J)J"),
+ NATIVE_METHOD(NativeCrypto, X509_get_version, "(J)J"),
+ NATIVE_METHOD(NativeCrypto, X509_get_serialNumber, "(J)[B"),
+ NATIVE_METHOD(NativeCrypto, X509_verify, "(JJ)V"),
+ NATIVE_METHOD(NativeCrypto, get_X509_cert_info_enc, "(J)[B"),
+ NATIVE_METHOD(NativeCrypto, get_X509_signature, "(J)[B"),
+ NATIVE_METHOD(NativeCrypto, get_X509_CRL_signature, "(J)[B"),
+ NATIVE_METHOD(NativeCrypto, get_X509_ex_flags, "(J)I"),
+ NATIVE_METHOD(NativeCrypto, d2i_X509_CRL_bio, "(J)J"),
+ NATIVE_METHOD(NativeCrypto, PEM_read_bio_X509_CRL, "(J)J"),
+ NATIVE_METHOD(NativeCrypto, X509_CRL_get0_by_cert, "(JJ)J"),
+ NATIVE_METHOD(NativeCrypto, X509_CRL_get0_by_serial, "(J[B)J"),
+ NATIVE_METHOD(NativeCrypto, X509_CRL_get_REVOKED, "(J)[J"),
+ NATIVE_METHOD(NativeCrypto, i2d_X509_CRL, "(J)[B"),
+ NATIVE_METHOD(NativeCrypto, X509_CRL_free, "(J)V"),
+ NATIVE_METHOD(NativeCrypto, X509_CRL_print, "(JJ)V"),
+ NATIVE_METHOD(NativeCrypto, get_X509_CRL_sig_alg_oid, "(J)Ljava/lang/String;"),
+ NATIVE_METHOD(NativeCrypto, get_X509_CRL_sig_alg_parameter, "(J)[B"),
+ NATIVE_METHOD(NativeCrypto, X509_CRL_get_issuer_name, "(J)[B"),
+ NATIVE_METHOD(NativeCrypto, X509_CRL_get_version, "(J)J"),
+ NATIVE_METHOD(NativeCrypto, X509_CRL_get_ext, "(JLjava/lang/String;)J"),
+ NATIVE_METHOD(NativeCrypto, X509_REVOKED_get_ext, "(JLjava/lang/String;)J"),
+ NATIVE_METHOD(NativeCrypto, X509_REVOKED_dup, "(J)J"),
+ NATIVE_METHOD(NativeCrypto, i2d_X509_REVOKED, "(J)[B"),
+ NATIVE_METHOD(NativeCrypto, X509_supported_extension, "(J)I"),
+ NATIVE_METHOD(NativeCrypto, ASN1_TIME_to_Calendar, "(JLjava/util/Calendar;)V"),
NATIVE_METHOD(NativeCrypto, SSL_CTX_new, "()J"),
NATIVE_METHOD(NativeCrypto, SSL_CTX_free, "(J)V"),
NATIVE_METHOD(NativeCrypto, SSL_CTX_set_session_id_context, "(J[B)V"),
@@ -6214,6 +7702,7 @@
NATIVE_METHOD(NativeCrypto, SSL_get_npn_negotiated_protocol, "(J)[B"),
NATIVE_METHOD(NativeCrypto, ERR_peek_last_error, "()J"),
};
+
void register_org_apache_harmony_xnet_provider_jsse_NativeCrypto(JNIEnv* env) {
JNI_TRACE("register_org_apache_harmony_xnet_provider_jsse_NativeCrypto");
jniRegisterNativeMethods(env, "org/apache/harmony/xnet/provider/jsse/NativeCrypto",
@@ -6229,8 +7718,11 @@
abort();
}
+ calendar_setMethod = env->GetMethodID(JniConstants::calendarClass, "set", "(IIIIII)V");
inputStream_readMethod = env->GetMethodID(JniConstants::inputStreamClass, "read", "([B)I");
- openSslInputStream_readLineMethod = env->GetMethodID(openSslOutputStreamClass, "readLine",
+ integer_valueOfMethod = env->GetStaticMethodID(JniConstants::integerClass, "valueOf",
+ "(I)Ljava/lang/Integer;");
+ openSslInputStream_readLineMethod = env->GetMethodID(openSslOutputStreamClass, "gets",
"([B)I");
outputStream_writeMethod = env->GetMethodID(JniConstants::outputStreamClass, "write", "([B)V");
outputStream_flushMethod = env->GetMethodID(JniConstants::outputStreamClass, "flush", "()V");