1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package org.conscrypt; 18 19 import java.security.cert.CertificateException; 20 import java.security.cert.X509Certificate; 21 import java.security.interfaces.DSAPublicKey; 22 import java.security.interfaces.ECPublicKey; 23 import java.security.interfaces.RSAPublicKey; 24 import java.util.List; 25 26 /** 27 * Analyzes the cryptographic strength of a chain of X.509 certificates. 28 * 29 * @hide 30 */ 31 @Internal 32 public final class ChainStrengthAnalyzer { 33 34 private static final int MIN_RSA_MODULUS_LEN_BITS = 1024; 35 36 private static final int MIN_EC_FIELD_SIZE_BITS = 160; 37 38 private static final int MIN_DSA_P_LEN_BITS = 1024; 39 private static final int MIN_DSA_Q_LEN_BITS = 160; 40 41 private static final String[] SIGNATURE_ALGORITHM_OID_BLACKLIST = { 42 "1.2.840.113549.1.1.2", // md2WithRSAEncryption 43 "1.2.840.113549.1.1.3", // md4WithRSAEncryption 44 "1.2.840.113549.1.1.4", // md5WithRSAEncryption 45 }; 46 47 public static final void check(X509Certificate[] chain) throws CertificateException { 48 for (X509Certificate cert : chain) { 49 try { 50 checkCert(cert); 51 } catch (CertificateException e) { 52 throw new CertificateException("Unacceptable certificate: " 53 + cert.getSubjectX500Principal(), e); 54 } 55 } 56 } 57 58 public static final void check(List<X509Certificate> chain) throws CertificateException { 59 for (X509Certificate cert : chain) { 60 try { 61 checkCert(cert); 62 } catch (CertificateException e) { 63 throw new CertificateException("Unacceptable certificate: " 64 + cert.getSubjectX500Principal(), e); 65 } 66 } 67 } 68 69 public static final void checkCert(X509Certificate cert) throws CertificateException { 70 checkKeyLength(cert); 71 checkSignatureAlgorithm(cert); 72 } 73 74 private static void checkKeyLength(X509Certificate cert) throws CertificateException { 75 Object pubkey = cert.getPublicKey(); 76 if (pubkey instanceof RSAPublicKey) { 77 int modulusLength = ((RSAPublicKey) pubkey).getModulus().bitLength(); 78 if (modulusLength < MIN_RSA_MODULUS_LEN_BITS) { 79 throw new CertificateException( 80 "RSA modulus is < " + MIN_RSA_MODULUS_LEN_BITS + " bits"); 81 } 82 } else if (pubkey instanceof ECPublicKey) { 83 int fieldSizeBits = 84 ((ECPublicKey) pubkey).getParams().getCurve().getField().getFieldSize(); 85 if (fieldSizeBits < MIN_EC_FIELD_SIZE_BITS) { 86 throw new CertificateException( 87 "EC key field size is < " + MIN_EC_FIELD_SIZE_BITS + " bits"); 88 } 89 } else if (pubkey instanceof DSAPublicKey) { 90 int pLength = ((DSAPublicKey) pubkey).getParams().getP().bitLength(); 91 int qLength = ((DSAPublicKey) pubkey).getParams().getQ().bitLength(); 92 if ((pLength < MIN_DSA_P_LEN_BITS) || (qLength < MIN_DSA_Q_LEN_BITS)) { 93 throw new CertificateException( 94 "DSA key length is < (" + MIN_DSA_P_LEN_BITS + ", " + MIN_DSA_Q_LEN_BITS 95 + ") bits"); 96 } 97 } else { 98 // Unknown keys will be of type X509PublicKey. 99 throw new CertificateException("Rejecting unknown key class " + pubkey.getClass().getName()); 100 } 101 } 102 103 private static void checkSignatureAlgorithm( 104 X509Certificate cert) throws CertificateException { 105 String oid = cert.getSigAlgOID(); 106 for (String blacklisted : SIGNATURE_ALGORITHM_OID_BLACKLIST) { 107 if (oid.equals(blacklisted)) { 108 throw new CertificateException("Signature uses an insecure hash function: " + oid); 109 } 110 } 111 } 112 } 113 114