Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2ae509b5 authored by Jesse Wilson's avatar Jesse Wilson Committed by Android (Google) Code Review
Browse files

Merge "Move the frameworks/base hostname verifier into libcore. Part 2/2"

parents c1bac3a6 52cd299e
Loading
Loading
Loading
Loading
+11 −17
Original line number Diff line number Diff line
@@ -17,28 +17,16 @@
package android.net.http;


import com.android.internal.net.DomainNameValidator;

import org.apache.harmony.security.provider.cert.X509CertImpl;
import org.apache.harmony.xnet.provider.jsse.SSLParametersImpl;

import java.io.IOException;

import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateExpiredException;
import java.security.cert.CertificateNotYetValidException;
import java.security.cert.X509Certificate;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.util.Date;

import javax.net.ssl.DefaultHostnameVerifier;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import org.apache.harmony.security.provider.cert.X509CertImpl;
import org.apache.harmony.xnet.provider.jsse.SSLParametersImpl;

/**
 * Class responsible for all server certificate validation functionality
@@ -53,6 +41,9 @@ class CertificateChainValidator {
    private static final CertificateChainValidator sInstance
            = new CertificateChainValidator();

    private static final DefaultHostnameVerifier sVerifier
            = new DefaultHostnameVerifier();

    /**
     * @return The singleton instance of the certificates chain validator
     */
@@ -147,7 +138,10 @@ class CertificateChainValidator {
            throw new IllegalArgumentException("certificate for this site is null");
        }

        if (!DomainNameValidator.match(currCertificate, domain)) {
        boolean valid = domain != null
                && !domain.isEmpty()
                && sVerifier.verify(domain, currCertificate);
        if (!valid) {
            if (HttpLog.LOGV) {
                HttpLog.v("certificate not for this host: " + domain);
            }
+0 −450
Original line number Diff line number Diff line
/*
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You 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 com.android.internal.net;


import android.util.Log;

import java.io.IOException;

import javax.security.auth.x500.X500Principal;

/**
 * A simple distinguished name(DN) parser.
 *
 * <p>This class is based on org.apache.harmony.security.x509.DNParser.  It's customized to remove
 * external references which are unnecessary for our requirements.
 *
 * <p>This class is only meant for extracting a string value from a DN.  e.g. it doesn't support
 * values in the hex-string style.
 *
 * <p>This class is used by {@link DomainNameValidator} only.  However, in order to make this
 * class visible from unit tests, it's made public.
 * 
 * @hide
 */
public final class DNParser {
    private static final String TAG = "DNParser";

    /** DN to be parsed. */
    private final String dn;

    // length of distinguished name string
    private final int length;

    private int pos, beg, end;

    // tmp vars to store positions of the currently parsed item
    private int cur;

    // distinguished name chars
    private char[] chars;

    /**
     * Exception message thrown when we failed to parse DN, which shouldn't happen because we
     * only handle DNs that {@link X500Principal#getName} returns, which shouldn't be malformed.
     */
    private static final String ERROR_PARSE_ERROR = "Failed to parse DN";

    /**
     * Constructor.
     *
     * @param principal - {@link X500Principal} to be parsed
     */
    public DNParser(X500Principal principal) {
        this.dn = principal.getName(X500Principal.RFC2253);
        this.length = dn.length();
    }

    // gets next attribute type: (ALPHA 1*keychar) / oid
    private String nextAT() throws IOException {

        // skip preceding space chars, they can present after
        // comma or semicolon (compatibility with RFC 1779)
        for (; pos < length && chars[pos] == ' '; pos++) {
        }
        if (pos == length) {
            return null; // reached the end of DN
        }

        // mark the beginning of attribute type
        beg = pos;

        // attribute type chars
        pos++;
        for (; pos < length && chars[pos] != '=' && chars[pos] != ' '; pos++) {
            // we don't follow exact BNF syntax here:
            // accept any char except space and '='
        }
        if (pos >= length) {
            // unexpected end of DN
            throw new IOException(ERROR_PARSE_ERROR);
        }

        // mark the end of attribute type
        end = pos;

        // skip trailing space chars between attribute type and '='
        // (compatibility with RFC 1779)
        if (chars[pos] == ' ') {
            for (; pos < length && chars[pos] != '=' && chars[pos] == ' '; pos++) {
            }

            if (chars[pos] != '=' || pos == length) {
                // unexpected end of DN
                throw new IOException(ERROR_PARSE_ERROR);
            }
        }

        pos++; //skip '=' char

        // skip space chars between '=' and attribute value
        // (compatibility with RFC 1779)
        for (; pos < length && chars[pos] == ' '; pos++) {
        }

        // in case of oid attribute type skip its prefix: "oid." or "OID."
        // (compatibility with RFC 1779)
        if ((end - beg > 4) && (chars[beg + 3] == '.')
                && (chars[beg] == 'O' || chars[beg] == 'o')
                && (chars[beg + 1] == 'I' || chars[beg + 1] == 'i')
                && (chars[beg + 2] == 'D' || chars[beg + 2] == 'd')) {
            beg += 4;
        }

        return new String(chars, beg, end - beg);
    }

    // gets quoted attribute value: QUOTATION *( quotechar / pair ) QUOTATION
    private String quotedAV() throws IOException {

        pos++;
        beg = pos;
        end = beg;
        while (true) {

            if (pos == length) {
                // unexpected end of DN
                throw new IOException(ERROR_PARSE_ERROR);
            }

            if (chars[pos] == '"') {
                // enclosing quotation was found
                pos++;
                break;
            } else if (chars[pos] == '\\') {
                chars[end] = getEscaped();
            } else {
                // shift char: required for string with escaped chars
                chars[end] = chars[pos];
            }
            pos++;
            end++;
        }

        // skip trailing space chars before comma or semicolon.
        // (compatibility with RFC 1779)
        for (; pos < length && chars[pos] == ' '; pos++) {
        }

        return new String(chars, beg, end - beg);
    }

    // gets hex string attribute value: "#" hexstring
    private String hexAV() throws IOException {

        if (pos + 4 >= length) {
            // encoded byte array  must be not less then 4 c
            throw new IOException(ERROR_PARSE_ERROR);
        }

        beg = pos; // store '#' position
        pos++;
        while (true) {

            // check for end of attribute value
            // looks for space and component separators
            if (pos == length || chars[pos] == '+' || chars[pos] == ','
                    || chars[pos] == ';') {
                end = pos;
                break;
            }

            if (chars[pos] == ' ') {
                end = pos;
                pos++;
                // skip trailing space chars before comma or semicolon.
                // (compatibility with RFC 1779)
                for (; pos < length && chars[pos] == ' '; pos++) {
                }
                break;
            } else if (chars[pos] >= 'A' && chars[pos] <= 'F') {
                chars[pos] += 32; //to low case
            }

            pos++;
        }

        // verify length of hex string
        // encoded byte array  must be not less then 4 and must be even number
        int hexLen = end - beg; // skip first '#' char
        if (hexLen < 5 || (hexLen & 1) == 0) {
            throw new IOException(ERROR_PARSE_ERROR);
        }

        // get byte encoding from string representation
        byte[] encoded = new byte[hexLen / 2];
        for (int i = 0, p = beg + 1; i < encoded.length; p += 2, i++) {
            encoded[i] = (byte) getByte(p);
        }

        return new String(chars, beg, hexLen);
    }

    // gets string attribute value: *( stringchar / pair )
    private String escapedAV() throws IOException {

        beg = pos;
        end = pos;
        while (true) {

            if (pos >= length) {
                // the end of DN has been found
                return new String(chars, beg, end - beg);
            }

            switch (chars[pos]) {
            case '+':
            case ',':
            case ';':
                // separator char has beed found
                return new String(chars, beg, end - beg);
            case '\\':
                // escaped char
                chars[end++] = getEscaped();
                pos++;
                break;
            case ' ':
                // need to figure out whether space defines
                // the end of attribute value or not
                cur = end;

                pos++;
                chars[end++] = ' ';

                for (; pos < length && chars[pos] == ' '; pos++) {
                    chars[end++] = ' ';
                }
                if (pos == length || chars[pos] == ',' || chars[pos] == '+'
                        || chars[pos] == ';') {
                    // separator char or the end of DN has beed found
                    return new String(chars, beg, cur - beg);
                }
                break;
            default:
                chars[end++] = chars[pos];
                pos++;
            }
        }
    }

    // returns escaped char
    private char getEscaped() throws IOException {

        pos++;
        if (pos == length) {
            throw new IOException(ERROR_PARSE_ERROR);
        }

        switch (chars[pos]) {
        case '"':
        case '\\':
        case ',':
        case '=':
        case '+':
        case '<':
        case '>':
        case '#':
        case ';':
        case ' ':
        case '*':
        case '%':
        case '_':
            //FIXME: escaping is allowed only for leading or trailing space char
            return chars[pos];
        default:
            // RFC doesn't explicitly say that escaped hex pair is
            // interpreted as UTF-8 char. It only contains an example of such DN.
            return getUTF8();
        }
    }

    // decodes UTF-8 char
    // see http://www.unicode.org for UTF-8 bit distribution table
    private char getUTF8() throws IOException {

        int res = getByte(pos);
        pos++; //FIXME tmp

        if (res < 128) { // one byte: 0-7F
            return (char) res;
        } else if (res >= 192 && res <= 247) {

            int count;
            if (res <= 223) { // two bytes: C0-DF
                count = 1;
                res = res & 0x1F;
            } else if (res <= 239) { // three bytes: E0-EF
                count = 2;
                res = res & 0x0F;
            } else { // four bytes: F0-F7
                count = 3;
                res = res & 0x07;
            }

            int b;
            for (int i = 0; i < count; i++) {
                pos++;
                if (pos == length || chars[pos] != '\\') {
                    return 0x3F; //FIXME failed to decode UTF-8 char - return '?'
                }
                pos++;

                b = getByte(pos);
                pos++; //FIXME tmp
                if ((b & 0xC0) != 0x80) {
                    return 0x3F; //FIXME failed to decode UTF-8 char - return '?'
                }

                res = (res << 6) + (b & 0x3F);
            }
            return (char) res;
        } else {
            return 0x3F; //FIXME failed to decode UTF-8 char - return '?'
        }
    }

    // Returns byte representation of a char pair
    // The char pair is composed of DN char in
    // specified 'position' and the next char
    // According to BNF syntax:
    // hexchar    = DIGIT / "A" / "B" / "C" / "D" / "E" / "F"
    //                    / "a" / "b" / "c" / "d" / "e" / "f"
    private int getByte(int position) throws IOException {

        if ((position + 1) >= length) {
            // to avoid ArrayIndexOutOfBoundsException
            throw new IOException(ERROR_PARSE_ERROR);
        }

        int b1, b2;

        b1 = chars[position];
        if (b1 >= '0' && b1 <= '9') {
            b1 = b1 - '0';
        } else if (b1 >= 'a' && b1 <= 'f') {
            b1 = b1 - 87; // 87 = 'a' - 10
        } else if (b1 >= 'A' && b1 <= 'F') {
            b1 = b1 - 55; // 55 = 'A' - 10
        } else {
            throw new IOException(ERROR_PARSE_ERROR);
        }

        b2 = chars[position + 1];
        if (b2 >= '0' && b2 <= '9') {
            b2 = b2 - '0';
        } else if (b2 >= 'a' && b2 <= 'f') {
            b2 = b2 - 87; // 87 = 'a' - 10
        } else if (b2 >= 'A' && b2 <= 'F') {
            b2 = b2 - 55; // 55 = 'A' - 10
        } else {
            throw new IOException(ERROR_PARSE_ERROR);
        }

        return (b1 << 4) + b2;
    }

    /**
     * Parses the DN and returns the attribute value for an attribute type.
     *
     * @param attributeType attribute type to look for (e.g. "ca")
     * @return value of the attribute that first found, or null if none found
     */
    public String find(String attributeType) {
        try {
            // Initialize internal state.
            pos = 0;
            beg = 0;
            end = 0;
            cur = 0;
            chars = dn.toCharArray();

            String attType = nextAT();
            if (attType == null) {
                return null;
            }
            while (true) {
                String attValue = "";

                if (pos == length) {
                    return null;
                }

                switch (chars[pos]) {
                case '"':
                    attValue = quotedAV();
                    break;
                case '#':
                    attValue = hexAV();
                    break;
                case '+':
                case ',':
                case ';': // compatibility with RFC 1779: semicolon can separate RDNs
                    //empty attribute value
                    break;
                default:
                    attValue = escapedAV();
                }

                if (attributeType.equalsIgnoreCase(attType)) {
                    return attValue;
                }

                if (pos >= length) {
                    return null;
                }

                if (chars[pos] == ',' || chars[pos] == ';') {
                } else if (chars[pos] != '+') {
                    throw new IOException(ERROR_PARSE_ERROR);
                }

                pos++;
                attType = nextAT();
                if (attType == null) {
                    throw new IOException(ERROR_PARSE_ERROR);
                }
            }
        } catch (IOException e) {
            // Parse error shouldn't happen, because we only handle DNs that
            // X500Principal.getName() returns, which shouldn't be malformed.
            Log.e(TAG, "Failed to parse DN: " + dn);
            return null;
        }
    }
}
+0 −260

File deleted.

Preview size limit exceeded, changes collapsed.

+0 −17
Original line number Diff line number Diff line
-----BEGIN CERTIFICATE-----
MIICsjCCAZqgAwIBAgIJALrC37YAXFIeMA0GCSqGSIb3DQEBBQUAMA0xCzAJBgNV
BAYTAkpQMCAXDTEwMDExMjIxMzk0NloYDzIwNjQxMDE1MjEzOTQ2WjANMQswCQYD
VQQGEwJKUDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALr8s/4Abpby
IYks5YCJE2nbWH7kj6XbwnRzsVP9RVC33bPoQ1M+2ZY24HqkigjQS/HEXR0s0bYh
dewNUnTj1uGyGs6cYzsbu7x114vmVYqjxUo3hKjwfYiPeF6f3IE1vpLI7I2G32gq
Zwm9c1/vXNHIdWQxCpFcuPA8P3YGfoApFX4pQPFplBUNAQqnjdmA68cbxxMC+1F3
mX42D7iIEVwyVpah5HjyxjIZQlf3X7QBj0bCmkL+ibIHTALrkNNwNM6i4xzYLz/5
14GkN9ncHY87eSOk6r53ptER6mQMhCe9qPRjSHnpWTTyj6IXTaYe+dDQw657B80w
cSHL7Ed25zUCAwEAAaMTMBEwDwYDVR0RBAgwBocEwKgKATANBgkqhkiG9w0BAQUF
AAOCAQEAgrwrtOWZT3fbi1AafpGaAiOBWSJqYqRhtQy0AfiZBxv1U0XaYqmZmpnq
DVAqr0NkljowD28NBrxIFO5gBNum2ZOPDl2/5vjFn+IirUCJ9u9wS7zYkTCW2lQR
xE7Ic3mfWv7wUbKDfjlWqP1IDHUxwkrBTAl+HnwOPiaKKk1ttwcrgS8AHlqASe03
mlwnvJ+Stk54IneRaegL0L93sNAy63RZqnPCTxGz7eHcFwX8Jdr4sbxTxQqV6pIc
WPjHQcWfpkFzAF5wyOq0kveVfx0g5xPhOVDd+U+q7WastbXICpCoHp9FxISmZVik
sAyifp8agkYdzaSh55fFmKXlFnRsQw==
-----END CERTIFICATE-----
+0 −17
Original line number Diff line number Diff line
-----BEGIN CERTIFICATE-----
MIICvTCCAaWgAwIBAgIJALbA0TZk2YmNMA0GCSqGSIb3DQEBBQUAMA0xCzAJBgNV
BAYTAkpQMCAXDTEwMDExMjIwNTg1NFoYDzIwNjQxMDE1MjA1ODU0WjANMQswCQYD
VQQGEwJKUDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMEg6acVC9V4
xNGoLNVLPbqBc8IvMvcsc88dF6MW3d9VagX3aeWU8c79tI/KOV/1AOakH7WYxw/w
yD8aOX7+9BK1Hu0qKKKbSM+ycqaMthXd6xytrNDsIx5WiGUz8zTko0Gk3orIR7p7
rPcNzB/zwtESkscqPv85aEn7S/yClNkzLfEzm3CtaYOc0tfhBMyzi/ipXzGMxUmx
PvOLr3v/Oz5pZEQw7Kxlm4+tAtn7bJlHziQ1UW4WPIy+T3hySBEpODFiqZi7Ok3X
Zjxdii62fgo5B2Ee7q5Amo0mUIwcQTDjJ2CLAqzYnSh3tpiPJGjEIjmRyCoMQ1bx
7D+y7nSPIq8CAwEAAaMeMBwwGgYDVR0RBBMwEYIPd3d3LmV4YW1wbGUuY29tMA0G
CSqGSIb3DQEBBQUAA4IBAQBsGEh+nHc0l9FJTzWqvG3qs7i6XoJZdtThCDx4HjKJ
8GMrJtreNN4JvIxn7KC+alVbnILjzCRO+c3rsnpxKBi5cp2imjuw5Kf/x2Seimb9
UvZbaJvBVOzy4Q1IGef9bLy3wZzy2/WfBFyvPTAkgkRaX7LN2jnYOYVhNoNFrwqe
EWxkA6fzrpyseUEFeGFFjGxRSRCDcQ25Eq6d9rkC1x21zNtt4QwZBO0wHrTy155M
JPRynf9244Pn0Sr/wsnmdsTRFIFYynrc51hQ7DkwbUxpcaewkZzilru/SwZ3+pPT
9JSqm5hJ1pg5WDlPkW7c/1VA0/141N52Q8MIU+2ZpuOj
-----END CERTIFICATE-----
Loading