All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.conscrypt.CertificatePriorityComparator Maven / Gradle / Ivy

There is a newer version: 2.0.42.rc
Show newest version
/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.conscrypt;

import java.security.PublicKey;
import java.security.cert.X509Certificate;
import java.security.interfaces.ECPublicKey;
import java.security.interfaces.RSAPublicKey;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

/**
 * {@link Comparator} for prioritizing certificates in path building.
 *
 * 

* The sort order is as follows: *

    *
  1. Self-issued certificates first.
  2. *
  3. Strength of certificates descending (EC before RSA, key size descending, signature * algorithm strength descending).
  4. *
  5. notAfter date descending.
  6. *
  7. notBefore date descending.
  8. *
*

*/ @Internal public final class CertificatePriorityComparator implements Comparator { /** * Map of signature algorithm OIDs to priorities. OIDs with a lower priority will be sorted * before those with higher. */ private static final Map ALGORITHM_OID_PRIORITY_MAP; /* * Priorities of digest algorithms. Lower is better. */ private static final Integer PRIORITY_MD5 = 6; private static final Integer PRIORITY_SHA1 = 5; private static final Integer PRIORITY_SHA224 = 4; private static final Integer PRIORITY_SHA256 = 3; private static final Integer PRIORITY_SHA384 = 2; private static final Integer PRIORITY_SHA512 = 1; private static final Integer PRIORITY_UNKNOWN = -1; static { ALGORITHM_OID_PRIORITY_MAP = new HashMap(); // RSA oids ALGORITHM_OID_PRIORITY_MAP.put("1.2.840.113549.1.1.13", PRIORITY_SHA512); ALGORITHM_OID_PRIORITY_MAP.put("1.2.840.113549.1.1.12", PRIORITY_SHA384); ALGORITHM_OID_PRIORITY_MAP.put("1.2.840.113549.1.1.11", PRIORITY_SHA256); ALGORITHM_OID_PRIORITY_MAP.put("1.2.840.113549.1.1.14", PRIORITY_SHA224); ALGORITHM_OID_PRIORITY_MAP.put("1.2.840.113549.1.1.5", PRIORITY_SHA1); ALGORITHM_OID_PRIORITY_MAP.put("1.2.840.113549.1.1.4", PRIORITY_MD5); // ECDSA oids ALGORITHM_OID_PRIORITY_MAP.put("1.2.840.10045.4.3.4", PRIORITY_SHA512); ALGORITHM_OID_PRIORITY_MAP.put("1.2.840.10045.4.3.3", PRIORITY_SHA384); ALGORITHM_OID_PRIORITY_MAP.put("1.2.840.10045.4.3.2", PRIORITY_SHA256); ALGORITHM_OID_PRIORITY_MAP.put("1.2.840.10045.4.3.1", PRIORITY_SHA224); ALGORITHM_OID_PRIORITY_MAP.put("1.2.840.10045.4.1", PRIORITY_SHA1); } @Override public int compare(X509Certificate lhs, X509Certificate rhs) { int result; boolean lhsSelfSigned = lhs.getSubjectDN().equals(lhs.getIssuerDN()); boolean rhsSelfSigned = rhs.getSubjectDN().equals(rhs.getIssuerDN()); // Self-issued before not self-issued to avoid trying bridge certs first. if (lhsSelfSigned != rhsSelfSigned) { return rhsSelfSigned ? 1 : -1; } // Strength descending. result = compareStrength(rhs, lhs); if (result != 0) { return result; } // notAfter descending. Date lhsNotAfter = lhs.getNotAfter(); Date rhsNotAfter = rhs.getNotAfter(); result = rhsNotAfter.compareTo(lhsNotAfter); if (result != 0) { return result; } // notBefore descending. Date lhsNotBefore = lhs.getNotBefore(); Date rhsNotBefore = rhs.getNotBefore(); return rhsNotBefore.compareTo(lhsNotBefore); } private int compareStrength(X509Certificate lhs, X509Certificate rhs) { int result; PublicKey lhsPublicKey = lhs.getPublicKey(); PublicKey rhsPublicKey = rhs.getPublicKey(); result = compareKeyAlgorithm(lhsPublicKey, rhsPublicKey); if (result != 0) { return result; } result = compareKeySize(lhsPublicKey, rhsPublicKey); if (result != 0) { return result; } return compareSignatureAlgorithm(lhs, rhs); } private int compareKeyAlgorithm(PublicKey lhs, PublicKey rhs) { String lhsAlgorithm = lhs.getAlgorithm().toUpperCase(Locale.US); String rhsAlgorithm = rhs.getAlgorithm().toUpperCase(Locale.US); if (lhsAlgorithm.equals(rhsAlgorithm)) { return 0; } // Prefer EC to RSA. if ("EC".equals(lhsAlgorithm)) { return 1; } else { return -1; } } private int compareKeySize(PublicKey lhs, PublicKey rhs) { String lhsAlgorithm = lhs.getAlgorithm().toUpperCase(Locale.US); String rhsAlgorithm = rhs.getAlgorithm().toUpperCase(Locale.US); if (!lhsAlgorithm.equals(rhsAlgorithm)) { throw new IllegalArgumentException("Keys are not of the same type"); } int lhsSize = getKeySize(lhs); int rhsSize = getKeySize(rhs); return lhsSize - rhsSize; } private int getKeySize(PublicKey pkey) { if (pkey instanceof ECPublicKey) { return ((ECPublicKey) pkey).getParams().getCurve().getField().getFieldSize(); } else if (pkey instanceof RSAPublicKey) { return ((RSAPublicKey) pkey).getModulus().bitLength(); } else { throw new IllegalArgumentException( "Unsupported public key type: " + pkey.getClass().getName()); } } private int compareSignatureAlgorithm(X509Certificate lhs, X509Certificate rhs) { Integer lhsPriority = ALGORITHM_OID_PRIORITY_MAP.get(lhs.getSigAlgOID()); Integer rhsPriority = ALGORITHM_OID_PRIORITY_MAP.get(rhs.getSigAlgOID()); if (lhsPriority == null) { lhsPriority = PRIORITY_UNKNOWN; } if (rhsPriority == null) { rhsPriority = PRIORITY_UNKNOWN; } return rhsPriority - lhsPriority; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy