// 
// Decompiled by Procyon v0.6.0
// 

package org.bouncycastle.pkix;

import java.security.AccessController;
import java.security.Security;
import java.security.PrivilegedAction;
import org.bouncycastle.util.Strings;
import java.util.HashMap;
import java.security.AccessControlException;
import java.util.WeakHashMap;
import java.util.Map;
import org.bouncycastle.util.BigIntegers;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import java.io.IOException;
import org.bouncycastle.asn1.pkcs.RSAPublicKey;
import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.crypto.CryptoServicesRegistrar;
import org.bouncycastle.math.Primes;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.x9.X9FieldID;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.x9.X962Parameters;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import java.math.BigInteger;

public class SubjectPublicKeyInfoChecker
{
    private static final Cache validatedQs;
    private static final Cache validatedMods;
    private static final BigInteger SMALL_PRIMES_PRODUCT;
    
    public static void checkInfo(final SubjectPublicKeyInfo subjectPublicKeyInfo) {
        final ASN1ObjectIdentifier algorithm = subjectPublicKeyInfo.getAlgorithm().getAlgorithm();
        if (X9ObjectIdentifiers.id_ecPublicKey.equals(algorithm)) {
            final X962Parameters instance = X962Parameters.getInstance(subjectPublicKeyInfo.getAlgorithm().getParameters());
            if (instance.isImplicitlyCA() || instance.isNamedCurve()) {
                return;
            }
            final X9FieldID instance2 = X9FieldID.getInstance(ASN1Sequence.getInstance(instance.getParameters()).getObjectAt(1));
            if (instance2.getIdentifier().equals(X9FieldID.prime_field)) {
                final BigInteger value = ASN1Integer.getInstance(instance2.getParameters()).getValue();
                if (SubjectPublicKeyInfoChecker.validatedQs.contains(value)) {
                    return;
                }
                final int integer = Properties.asInteger("org.bouncycastle.ec.fp_max_size", 1042);
                final int integer2 = Properties.asInteger("org.bouncycastle.ec.fp_certainty", 100);
                final int bitLength = value.bitLength();
                if (integer < bitLength) {
                    throw new IllegalArgumentException("Fp q value out of range");
                }
                if (Primes.hasAnySmallFactors(value) || !Primes.isMRProbablePrime(value, CryptoServicesRegistrar.getSecureRandom(), getNumberOfIterations(bitLength, integer2))) {
                    throw new IllegalArgumentException("Fp q value not prime");
                }
                SubjectPublicKeyInfoChecker.validatedQs.add(value);
            }
        }
        else {
            if (!PKCSObjectIdentifiers.rsaEncryption.equals(algorithm) && !X509ObjectIdentifiers.id_ea_rsa.equals(algorithm) && !PKCSObjectIdentifiers.id_RSAES_OAEP.equals(algorithm)) {
                if (!PKCSObjectIdentifiers.id_RSASSA_PSS.equals(algorithm)) {
                    return;
                }
            }
            RSAPublicKey instance3;
            try {
                instance3 = RSAPublicKey.getInstance(subjectPublicKeyInfo.parsePublicKey());
            }
            catch (final IOException ex) {
                throw new IllegalArgumentException("unable to parse RSA key");
            }
            if ((instance3.getPublicExponent().intValue() & 0x1) == 0x0) {
                throw new IllegalArgumentException("RSA publicExponent is even");
            }
            if (!SubjectPublicKeyInfoChecker.validatedMods.contains(instance3.getModulus())) {
                validate(instance3.getModulus());
                SubjectPublicKeyInfoChecker.validatedMods.add(instance3.getModulus());
            }
        }
    }
    
    private static boolean hasAnySmallFactors(final BigInteger bigInteger) {
        BigInteger small_PRIMES_PRODUCT = bigInteger;
        BigInteger small_PRIMES_PRODUCT2 = SubjectPublicKeyInfoChecker.SMALL_PRIMES_PRODUCT;
        if (bigInteger.compareTo(SubjectPublicKeyInfoChecker.SMALL_PRIMES_PRODUCT) < 0) {
            small_PRIMES_PRODUCT = SubjectPublicKeyInfoChecker.SMALL_PRIMES_PRODUCT;
            small_PRIMES_PRODUCT2 = bigInteger;
        }
        return !BigIntegers.modOddIsCoprimeVar(small_PRIMES_PRODUCT, small_PRIMES_PRODUCT2);
    }
    
    private static void validate(final BigInteger bigInteger) {
        if ((bigInteger.intValue() & 0x1) == 0x0) {
            throw new IllegalArgumentException("RSA modulus is even");
        }
        if (Properties.isOverrideSet("org.bouncycastle.rsa.allow_unsafe_mod")) {
            return;
        }
        if (Properties.asInteger("org.bouncycastle.rsa.max_size", 16384) < bigInteger.bitLength()) {
            throw new IllegalArgumentException("RSA modulus out of range");
        }
        if (hasAnySmallFactors(bigInteger)) {
            throw new IllegalArgumentException("RSA modulus has a small prime factor");
        }
        final int n = bigInteger.bitLength() / 2;
        if (!Primes.enhancedMRProbablePrimeTest(bigInteger, CryptoServicesRegistrar.getSecureRandom(), (n >= 1536) ? 3 : ((n >= 1024) ? 4 : ((n >= 512) ? 7 : 50))).isProvablyComposite()) {
            throw new IllegalArgumentException("RSA modulus is not composite");
        }
    }
    
    private static int getNumberOfIterations(final int n, final int n2) {
        if (n >= 1536) {
            return (n2 <= 100) ? 3 : ((n2 <= 128) ? 4 : (4 + (n2 - 128 + 1) / 2));
        }
        if (n >= 1024) {
            return (n2 <= 100) ? 4 : ((n2 <= 112) ? 5 : (5 + (n2 - 112 + 1) / 2));
        }
        if (n >= 512) {
            return (n2 <= 80) ? 5 : ((n2 <= 100) ? 7 : (7 + (n2 - 100 + 1) / 2));
        }
        return (n2 <= 80) ? 40 : (40 + (n2 - 80 + 1) / 2);
    }
    
    public static boolean setThreadOverride(final String s, final boolean b) {
        return Properties.setThreadOverride(s, b);
    }
    
    public static boolean removeThreadOverride(final String s) {
        return Properties.removeThreadOverride(s);
    }
    
    static {
        validatedQs = new Cache();
        validatedMods = new Cache();
        SMALL_PRIMES_PRODUCT = new BigInteger("8138e8a0fcf3a4e84a771d40fd305d7f4aa59306d7251de54d98af8fe95729a1f73d893fa424cd2edc8636a6c3285e022b0e3866a565ae8108eed8591cd4fe8d2ce86165a978d719ebf647f362d33fca29cd179fb42401cbaf3df0c614056f9c8f3cfd51e474afb6bc6974f78db8aba8e9e517fded658591ab7502bd41849462f", 16);
    }
    
    private static class Cache
    {
        private final Map<BigInteger, Boolean> values;
        private final BigInteger[] preserve;
        private int preserveCounter;
        
        private Cache() {
            this.values = new WeakHashMap<BigInteger, Boolean>();
            this.preserve = new BigInteger[8];
            this.preserveCounter = 0;
        }
        
        public synchronized void add(final BigInteger bigInteger) {
            this.values.put(bigInteger, Boolean.TRUE);
            this.preserve[this.preserveCounter] = bigInteger;
            this.preserveCounter = (this.preserveCounter + 1) % this.preserve.length;
        }
        
        public synchronized boolean contains(final BigInteger bigInteger) {
            return this.values.containsKey(bigInteger);
        }
        
        public synchronized int size() {
            return this.values.size();
        }
        
        public synchronized void clear() {
            this.values.clear();
            for (int i = 0; i != this.preserve.length; ++i) {
                this.preserve[i] = null;
            }
        }
    }
    
    private static class Properties
    {
        private static final ThreadLocal threadProperties;
        
        static boolean isOverrideSet(final String s) {
            try {
                return isSetTrue(getPropertyValue(s));
            }
            catch (final AccessControlException ex) {
                return false;
            }
        }
        
        static boolean setThreadOverride(final String s, final boolean b) {
            final boolean overrideSet = isOverrideSet(s);
            Map value = Properties.threadProperties.get();
            if (value == null) {
                value = new HashMap();
                Properties.threadProperties.set(value);
            }
            value.put(s, b ? "true" : "false");
            return overrideSet;
        }
        
        static boolean removeThreadOverride(final String s) {
            final Map map = Properties.threadProperties.get();
            if (map != null) {
                final String s2 = (String)map.remove(s);
                if (s2 != null) {
                    if (map.isEmpty()) {
                        Properties.threadProperties.remove();
                    }
                    return "true".equals(Strings.toLowerCase(s2));
                }
            }
            return false;
        }
        
        static int asInteger(final String s, final int n) {
            final String propertyValue = getPropertyValue(s);
            if (propertyValue != null) {
                return Integer.parseInt(propertyValue);
            }
            return n;
        }
        
        static String getPropertyValue(final String s) {
            final String s2 = AccessController.doPrivileged((PrivilegedAction<String>)new PrivilegedAction() {
                @Override
                public Object run() {
                    return Security.getProperty(s);
                }
            });
            if (s2 != null) {
                return s2;
            }
            final Map map = Properties.threadProperties.get();
            if (map != null) {
                final String s3 = (String)map.get(s);
                if (s3 != null) {
                    return s3;
                }
            }
            return AccessController.doPrivileged((PrivilegedAction<String>)new PrivilegedAction() {
                @Override
                public Object run() {
                    return System.getProperty(s);
                }
            });
        }
        
        private static boolean isSetTrue(final String s) {
            return s != null && s.length() == 4 && (s.charAt(0) == 't' || s.charAt(0) == 'T') && (s.charAt(1) == 'r' || s.charAt(1) == 'R') && (s.charAt(2) == 'u' || s.charAt(2) == 'U') && (s.charAt(3) == 'e' || s.charAt(3) == 'E');
        }
        
        static {
            threadProperties = new ThreadLocal();
        }
    }
}
