Search in sources :

Example 36 with BufferUnderflowException

use of java.nio.BufferUnderflowException in project android_frameworks_base by DirtyUnicorns.

the class DhcpPacket method decodeFullPacket.

/**
     * Creates a concrete DhcpPacket from the supplied ByteBuffer.  The
     * buffer may have an L2 encapsulation (which is the full EthernetII
     * format starting with the source-address MAC) or an L3 encapsulation
     * (which starts with the IP header).
     * <br>
     * A subset of the optional parameters are parsed and are stored
     * in object fields.
     */
@VisibleForTesting
static DhcpPacket decodeFullPacket(ByteBuffer packet, int pktType) throws ParseException {
    // bootp parameters
    int transactionId;
    short secs;
    Inet4Address clientIp;
    Inet4Address yourIp;
    Inet4Address nextIp;
    Inet4Address relayIp;
    byte[] clientMac;
    List<Inet4Address> dnsServers = new ArrayList<>();
    // aka router
    List<Inet4Address> gateways = new ArrayList<>();
    Inet4Address serverIdentifier = null;
    Inet4Address netMask = null;
    String message = null;
    String vendorId = null;
    String vendorInfo = null;
    byte[] expectedParams = null;
    String hostName = null;
    String domainName = null;
    Inet4Address ipSrc = null;
    Inet4Address ipDst = null;
    Inet4Address bcAddr = null;
    Inet4Address requestedIp = null;
    // The following are all unsigned integers. Internally we store them as signed integers of
    // the same length because that way we're guaranteed that they can't be out of the range of
    // the unsigned field in the packet. Callers wanting to pass in an unsigned value will need
    // to cast it.
    Short mtu = null;
    Short maxMessageSize = null;
    Integer leaseTime = null;
    Integer T1 = null;
    Integer T2 = null;
    // dhcp options
    byte dhcpType = (byte) 0xFF;
    packet.order(ByteOrder.BIG_ENDIAN);
    // check to see if we need to parse L2, IP, and UDP encaps
    if (pktType == ENCAP_L2) {
        if (packet.remaining() < MIN_PACKET_LENGTH_L2) {
            throw new ParseException(DhcpErrorEvent.L2_TOO_SHORT, "L2 packet too short, %d < %d", packet.remaining(), MIN_PACKET_LENGTH_L2);
        }
        byte[] l2dst = new byte[6];
        byte[] l2src = new byte[6];
        packet.get(l2dst);
        packet.get(l2src);
        short l2type = packet.getShort();
        if (l2type != OsConstants.ETH_P_IP) {
            throw new ParseException(DhcpErrorEvent.L2_WRONG_ETH_TYPE, "Unexpected L2 type 0x%04x, expected 0x%04x", l2type, OsConstants.ETH_P_IP);
        }
    }
    if (pktType <= ENCAP_L3) {
        if (packet.remaining() < MIN_PACKET_LENGTH_L3) {
            throw new ParseException(DhcpErrorEvent.L3_TOO_SHORT, "L3 packet too short, %d < %d", packet.remaining(), MIN_PACKET_LENGTH_L3);
        }
        byte ipTypeAndLength = packet.get();
        int ipVersion = (ipTypeAndLength & 0xf0) >> 4;
        if (ipVersion != 4) {
            throw new ParseException(DhcpErrorEvent.L3_NOT_IPV4, "Invalid IP version %d", ipVersion);
        }
        // System.out.println("ipType is " + ipType);
        byte ipDiffServicesField = packet.get();
        short ipTotalLength = packet.getShort();
        short ipIdentification = packet.getShort();
        byte ipFlags = packet.get();
        byte ipFragOffset = packet.get();
        byte ipTTL = packet.get();
        byte ipProto = packet.get();
        short ipChksm = packet.getShort();
        ipSrc = readIpAddress(packet);
        ipDst = readIpAddress(packet);
        if (ipProto != IP_TYPE_UDP) {
            throw new ParseException(DhcpErrorEvent.L4_NOT_UDP, "Protocol not UDP: %d", ipProto);
        }
        // Skip options. This cannot cause us to read beyond the end of the buffer because the
        // IPv4 header cannot be more than (0x0f * 4) = 60 bytes long, and that is less than
        // MIN_PACKET_LENGTH_L3.
        int optionWords = ((ipTypeAndLength & 0x0f) - 5);
        for (int i = 0; i < optionWords; i++) {
            packet.getInt();
        }
        // assume UDP
        short udpSrcPort = packet.getShort();
        short udpDstPort = packet.getShort();
        short udpLen = packet.getShort();
        short udpChkSum = packet.getShort();
        // server-to-server packets, e.g. for relays.
        if (!isPacketToOrFromClient(udpSrcPort, udpDstPort) && !isPacketServerToServer(udpSrcPort, udpDstPort)) {
            // filter is set. http://b/26696823 .
            throw new ParseException(DhcpErrorEvent.L4_WRONG_PORT, "Unexpected UDP ports %d->%d", udpSrcPort, udpDstPort);
        }
    }
    // We need to check the length even for ENCAP_L3 because the IPv4 header is variable-length.
    if (pktType > ENCAP_BOOTP || packet.remaining() < MIN_PACKET_LENGTH_BOOTP) {
        throw new ParseException(DhcpErrorEvent.BOOTP_TOO_SHORT, "Invalid type or BOOTP packet too short, %d < %d", packet.remaining(), MIN_PACKET_LENGTH_BOOTP);
    }
    byte type = packet.get();
    byte hwType = packet.get();
    int addrLen = packet.get() & 0xff;
    byte hops = packet.get();
    transactionId = packet.getInt();
    secs = packet.getShort();
    short bootpFlags = packet.getShort();
    boolean broadcast = (bootpFlags & 0x8000) != 0;
    byte[] ipv4addr = new byte[4];
    try {
        packet.get(ipv4addr);
        clientIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr);
        packet.get(ipv4addr);
        yourIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr);
        packet.get(ipv4addr);
        nextIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr);
        packet.get(ipv4addr);
        relayIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr);
    } catch (UnknownHostException ex) {
        throw new ParseException(DhcpErrorEvent.L3_INVALID_IP, "Invalid IPv4 address: %s", Arrays.toString(ipv4addr));
    }
    // TODO: evaluate whether to make this test more liberal.
    if (addrLen > HWADDR_LEN) {
        addrLen = ETHER_BROADCAST.length;
    }
    clientMac = new byte[addrLen];
    packet.get(clientMac);
    // skip over address padding (16 octets allocated)
    packet.position(packet.position() + (16 - addrLen) + // skip server host name (64 chars)
    64 + // skip boot file name (128 chars)
    128);
    // Ensure this is a DHCP packet with a magic cookie, and not BOOTP. http://b/31850211
    if (packet.remaining() < 4) {
        throw new ParseException(DhcpErrorEvent.DHCP_NO_COOKIE, "not a DHCP message");
    }
    int dhcpMagicCookie = packet.getInt();
    if (dhcpMagicCookie != DHCP_MAGIC_COOKIE) {
        throw new ParseException(DhcpErrorEvent.DHCP_BAD_MAGIC_COOKIE, "Bad magic cookie 0x%08x, should be 0x%08x", dhcpMagicCookie, DHCP_MAGIC_COOKIE);
    }
    // parse options
    boolean notFinishedOptions = true;
    while ((packet.position() < packet.limit()) && notFinishedOptions) {
        // cannot underflow because position < limit
        final byte optionType = packet.get();
        try {
            if (optionType == DHCP_OPTION_END) {
                notFinishedOptions = false;
            } else if (optionType == DHCP_OPTION_PAD) {
            // The pad option doesn't have a length field. Nothing to do.
            } else {
                int optionLen = packet.get() & 0xFF;
                int expectedLen = 0;
                switch(optionType) {
                    case DHCP_SUBNET_MASK:
                        netMask = readIpAddress(packet);
                        expectedLen = 4;
                        break;
                    case DHCP_ROUTER:
                        for (expectedLen = 0; expectedLen < optionLen; expectedLen += 4) {
                            gateways.add(readIpAddress(packet));
                        }
                        break;
                    case DHCP_DNS_SERVER:
                        for (expectedLen = 0; expectedLen < optionLen; expectedLen += 4) {
                            dnsServers.add(readIpAddress(packet));
                        }
                        break;
                    case DHCP_HOST_NAME:
                        expectedLen = optionLen;
                        hostName = readAsciiString(packet, optionLen, false);
                        break;
                    case DHCP_MTU:
                        expectedLen = 2;
                        mtu = packet.getShort();
                        break;
                    case DHCP_DOMAIN_NAME:
                        expectedLen = optionLen;
                        domainName = readAsciiString(packet, optionLen, false);
                        break;
                    case DHCP_BROADCAST_ADDRESS:
                        bcAddr = readIpAddress(packet);
                        expectedLen = 4;
                        break;
                    case DHCP_REQUESTED_IP:
                        requestedIp = readIpAddress(packet);
                        expectedLen = 4;
                        break;
                    case DHCP_LEASE_TIME:
                        leaseTime = Integer.valueOf(packet.getInt());
                        expectedLen = 4;
                        break;
                    case DHCP_MESSAGE_TYPE:
                        dhcpType = packet.get();
                        expectedLen = 1;
                        break;
                    case DHCP_SERVER_IDENTIFIER:
                        serverIdentifier = readIpAddress(packet);
                        expectedLen = 4;
                        break;
                    case DHCP_PARAMETER_LIST:
                        expectedParams = new byte[optionLen];
                        packet.get(expectedParams);
                        expectedLen = optionLen;
                        break;
                    case DHCP_MESSAGE:
                        expectedLen = optionLen;
                        message = readAsciiString(packet, optionLen, false);
                        break;
                    case DHCP_MAX_MESSAGE_SIZE:
                        expectedLen = 2;
                        maxMessageSize = Short.valueOf(packet.getShort());
                        break;
                    case DHCP_RENEWAL_TIME:
                        expectedLen = 4;
                        T1 = Integer.valueOf(packet.getInt());
                        break;
                    case DHCP_REBINDING_TIME:
                        expectedLen = 4;
                        T2 = Integer.valueOf(packet.getInt());
                        break;
                    case DHCP_VENDOR_CLASS_ID:
                        expectedLen = optionLen;
                        // Embedded nulls are safe as this does not get passed to netd.
                        vendorId = readAsciiString(packet, optionLen, true);
                        break;
                    case DHCP_CLIENT_IDENTIFIER:
                        {
                            // Client identifier
                            byte[] id = new byte[optionLen];
                            packet.get(id);
                            expectedLen = optionLen;
                        }
                        break;
                    case DHCP_VENDOR_INFO:
                        expectedLen = optionLen;
                        // Embedded nulls are safe as this does not get passed to netd.
                        vendorInfo = readAsciiString(packet, optionLen, true);
                        break;
                    default:
                        // ignore any other parameters
                        for (int i = 0; i < optionLen; i++) {
                            expectedLen++;
                            byte throwaway = packet.get();
                        }
                }
                if (expectedLen != optionLen) {
                    final int errorCode = DhcpErrorEvent.errorCodeWithOption(DhcpErrorEvent.DHCP_INVALID_OPTION_LENGTH, optionType);
                    throw new ParseException(errorCode, "Invalid length %d for option %d, expected %d", optionLen, optionType, expectedLen);
                }
            }
        } catch (BufferUnderflowException e) {
            final int errorCode = DhcpErrorEvent.errorCodeWithOption(DhcpErrorEvent.BUFFER_UNDERFLOW, optionType);
            throw new ParseException(errorCode, "BufferUnderflowException");
        }
    }
    DhcpPacket newPacket;
    switch(dhcpType) {
        case (byte) 0xFF:
            throw new ParseException(DhcpErrorEvent.DHCP_NO_MSG_TYPE, "No DHCP message type option");
        case DHCP_MESSAGE_TYPE_DISCOVER:
            newPacket = new DhcpDiscoverPacket(transactionId, secs, clientMac, broadcast);
            break;
        case DHCP_MESSAGE_TYPE_OFFER:
            newPacket = new DhcpOfferPacket(transactionId, secs, broadcast, ipSrc, clientIp, yourIp, clientMac);
            break;
        case DHCP_MESSAGE_TYPE_REQUEST:
            newPacket = new DhcpRequestPacket(transactionId, secs, clientIp, clientMac, broadcast);
            break;
        case DHCP_MESSAGE_TYPE_DECLINE:
            newPacket = new DhcpDeclinePacket(transactionId, secs, clientIp, yourIp, nextIp, relayIp, clientMac);
            break;
        case DHCP_MESSAGE_TYPE_ACK:
            newPacket = new DhcpAckPacket(transactionId, secs, broadcast, ipSrc, clientIp, yourIp, clientMac);
            break;
        case DHCP_MESSAGE_TYPE_NAK:
            newPacket = new DhcpNakPacket(transactionId, secs, clientIp, yourIp, nextIp, relayIp, clientMac);
            break;
        case DHCP_MESSAGE_TYPE_INFORM:
            newPacket = new DhcpInformPacket(transactionId, secs, clientIp, yourIp, nextIp, relayIp, clientMac);
            break;
        default:
            throw new ParseException(DhcpErrorEvent.DHCP_UNKNOWN_MSG_TYPE, "Unimplemented DHCP type %d", dhcpType);
    }
    newPacket.mBroadcastAddress = bcAddr;
    newPacket.mDnsServers = dnsServers;
    newPacket.mDomainName = domainName;
    newPacket.mGateways = gateways;
    newPacket.mHostName = hostName;
    newPacket.mLeaseTime = leaseTime;
    newPacket.mMessage = message;
    newPacket.mMtu = mtu;
    newPacket.mRequestedIp = requestedIp;
    newPacket.mRequestedParams = expectedParams;
    newPacket.mServerIdentifier = serverIdentifier;
    newPacket.mSubnetMask = netMask;
    newPacket.mMaxMessageSize = maxMessageSize;
    newPacket.mT1 = T1;
    newPacket.mT2 = T2;
    newPacket.mVendorId = vendorId;
    newPacket.mVendorInfo = vendorInfo;
    return newPacket;
}
Also used : Inet4Address(java.net.Inet4Address) UnknownHostException(java.net.UnknownHostException) ArrayList(java.util.ArrayList) BufferUnderflowException(java.nio.BufferUnderflowException) VisibleForTesting(com.android.internal.annotations.VisibleForTesting)

Example 37 with BufferUnderflowException

use of java.nio.BufferUnderflowException in project android_frameworks_base by DirtyUnicorns.

the class IconCache method notifyIconReceived.

public void notifyIconReceived(long bssid, String fileName, byte[] iconData) {
    Log.d("ZXZ", String.format("Icon '%s':%d received from %012x", fileName, iconData != null ? iconData.length : -1, bssid));
    IconKey key;
    HSIconFileElement iconFileElement = null;
    List<OSUInfo> updates = new ArrayList<>();
    LinkedList<QuerySet> querySets = mBssQueues.get(bssid);
    if (querySets == null || querySets.isEmpty()) {
        Log.d(OSUManager.TAG, String.format("Spurious icon response from %012x for '%s' (%d) bytes", bssid, fileName, iconData != null ? iconData.length : -1));
        Log.d("ZXZ", "query set: " + querySets + ", BSS queues: " + Utils.bssidsToString(mBssQueues.keySet()));
        return;
    } else {
        QuerySet querySet = querySets.removeFirst();
        if (iconData != null) {
            try {
                iconFileElement = new HSIconFileElement(HSIconFile, ByteBuffer.wrap(iconData).order(ByteOrder.LITTLE_ENDIAN));
            } catch (ProtocolException | BufferUnderflowException e) {
                Log.e(OSUManager.TAG, "Failed to parse ANQP icon file: " + e);
            }
        }
        key = querySet.updateIcon(fileName, iconFileElement);
        if (key == null) {
            Log.d(OSUManager.TAG, String.format("Spurious icon response from %012x for '%s' (%d) bytes", bssid, fileName, iconData != null ? iconData.length : -1));
            Log.d("ZXZ", "query set: " + querySets + ", BSS queues: " + Utils.bssidsToString(mBssQueues.keySet()));
            querySets.addFirst(querySet);
            return;
        }
        if (iconFileElement != null) {
            mCache.put(key, iconFileElement);
        }
        if (querySet.isEmpty()) {
            mBssQueues.remove(bssid);
        }
        updates.add(querySet.getOsuInfo());
    }
    // Update any other pending entries that matches the ESS of the currently resolved icon
    Iterator<Map.Entry<Long, LinkedList<QuerySet>>> bssIterator = mBssQueues.entrySet().iterator();
    while (bssIterator.hasNext()) {
        Map.Entry<Long, LinkedList<QuerySet>> bssEntries = bssIterator.next();
        Iterator<QuerySet> querySetIterator = bssEntries.getValue().iterator();
        while (querySetIterator.hasNext()) {
            QuerySet querySet = querySetIterator.next();
            if (querySet.updateIcon(key, iconFileElement)) {
                querySetIterator.remove();
                updates.add(querySet.getOsuInfo());
            }
        }
        if (bssEntries.getValue().isEmpty()) {
            bssIterator.remove();
        }
    }
    initiateQuery(bssid);
    mOSUManager.iconResults(updates);
}
Also used : ProtocolException(java.net.ProtocolException) ArrayList(java.util.ArrayList) LinkedList(java.util.LinkedList) HSIconFileElement(com.android.anqp.HSIconFileElement) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) Map(java.util.Map) BufferUnderflowException(java.nio.BufferUnderflowException)

Example 38 with BufferUnderflowException

use of java.nio.BufferUnderflowException in project android_frameworks_base by DirtyUnicorns.

the class ApkSignatureSchemeV2Verifier method verifySigner.

private static X509Certificate[] verifySigner(ByteBuffer signerBlock, Map<Integer, byte[]> contentDigests, CertificateFactory certFactory) throws SecurityException, IOException {
    ByteBuffer signedData = getLengthPrefixedSlice(signerBlock);
    ByteBuffer signatures = getLengthPrefixedSlice(signerBlock);
    byte[] publicKeyBytes = readLengthPrefixedByteArray(signerBlock);
    int signatureCount = 0;
    int bestSigAlgorithm = -1;
    byte[] bestSigAlgorithmSignatureBytes = null;
    List<Integer> signaturesSigAlgorithms = new ArrayList<>();
    while (signatures.hasRemaining()) {
        signatureCount++;
        try {
            ByteBuffer signature = getLengthPrefixedSlice(signatures);
            if (signature.remaining() < 8) {
                throw new SecurityException("Signature record too short");
            }
            int sigAlgorithm = signature.getInt();
            signaturesSigAlgorithms.add(sigAlgorithm);
            if (!isSupportedSignatureAlgorithm(sigAlgorithm)) {
                continue;
            }
            if ((bestSigAlgorithm == -1) || (compareSignatureAlgorithm(sigAlgorithm, bestSigAlgorithm) > 0)) {
                bestSigAlgorithm = sigAlgorithm;
                bestSigAlgorithmSignatureBytes = readLengthPrefixedByteArray(signature);
            }
        } catch (IOException | BufferUnderflowException e) {
            throw new SecurityException("Failed to parse signature record #" + signatureCount, e);
        }
    }
    if (bestSigAlgorithm == -1) {
        if (signatureCount == 0) {
            throw new SecurityException("No signatures found");
        } else {
            throw new SecurityException("No supported signatures found");
        }
    }
    String keyAlgorithm = getSignatureAlgorithmJcaKeyAlgorithm(bestSigAlgorithm);
    Pair<String, ? extends AlgorithmParameterSpec> signatureAlgorithmParams = getSignatureAlgorithmJcaSignatureAlgorithm(bestSigAlgorithm);
    String jcaSignatureAlgorithm = signatureAlgorithmParams.first;
    AlgorithmParameterSpec jcaSignatureAlgorithmParams = signatureAlgorithmParams.second;
    boolean sigVerified;
    try {
        PublicKey publicKey = KeyFactory.getInstance(keyAlgorithm).generatePublic(new X509EncodedKeySpec(publicKeyBytes));
        Signature sig = Signature.getInstance(jcaSignatureAlgorithm);
        sig.initVerify(publicKey);
        if (jcaSignatureAlgorithmParams != null) {
            sig.setParameter(jcaSignatureAlgorithmParams);
        }
        sig.update(signedData);
        sigVerified = sig.verify(bestSigAlgorithmSignatureBytes);
    } catch (NoSuchAlgorithmException | InvalidKeySpecException | InvalidKeyException | InvalidAlgorithmParameterException | SignatureException e) {
        throw new SecurityException("Failed to verify " + jcaSignatureAlgorithm + " signature", e);
    }
    if (!sigVerified) {
        throw new SecurityException(jcaSignatureAlgorithm + " signature did not verify");
    }
    // Signature over signedData has verified.
    byte[] contentDigest = null;
    signedData.clear();
    ByteBuffer digests = getLengthPrefixedSlice(signedData);
    List<Integer> digestsSigAlgorithms = new ArrayList<>();
    int digestCount = 0;
    while (digests.hasRemaining()) {
        digestCount++;
        try {
            ByteBuffer digest = getLengthPrefixedSlice(digests);
            if (digest.remaining() < 8) {
                throw new IOException("Record too short");
            }
            int sigAlgorithm = digest.getInt();
            digestsSigAlgorithms.add(sigAlgorithm);
            if (sigAlgorithm == bestSigAlgorithm) {
                contentDigest = readLengthPrefixedByteArray(digest);
            }
        } catch (IOException | BufferUnderflowException e) {
            throw new IOException("Failed to parse digest record #" + digestCount, e);
        }
    }
    if (!signaturesSigAlgorithms.equals(digestsSigAlgorithms)) {
        throw new SecurityException("Signature algorithms don't match between digests and signatures records");
    }
    int digestAlgorithm = getSignatureAlgorithmContentDigestAlgorithm(bestSigAlgorithm);
    byte[] previousSignerDigest = contentDigests.put(digestAlgorithm, contentDigest);
    if ((previousSignerDigest != null) && (!MessageDigest.isEqual(previousSignerDigest, contentDigest))) {
        throw new SecurityException(getContentDigestAlgorithmJcaDigestAlgorithm(digestAlgorithm) + " contents digest does not match the digest specified by a preceding signer");
    }
    ByteBuffer certificates = getLengthPrefixedSlice(signedData);
    List<X509Certificate> certs = new ArrayList<>();
    int certificateCount = 0;
    while (certificates.hasRemaining()) {
        certificateCount++;
        byte[] encodedCert = readLengthPrefixedByteArray(certificates);
        X509Certificate certificate;
        try {
            certificate = (X509Certificate) certFactory.generateCertificate(new ByteArrayInputStream(encodedCert));
        } catch (CertificateException e) {
            throw new SecurityException("Failed to decode certificate #" + certificateCount, e);
        }
        certificate = new VerbatimX509Certificate(certificate, encodedCert);
        certs.add(certificate);
    }
    if (certs.isEmpty()) {
        throw new SecurityException("No certificates listed");
    }
    X509Certificate mainCertificate = certs.get(0);
    byte[] certificatePublicKeyBytes = mainCertificate.getPublicKey().getEncoded();
    if (!Arrays.equals(publicKeyBytes, certificatePublicKeyBytes)) {
        throw new SecurityException("Public key mismatch between certificate and signature record");
    }
    return certs.toArray(new X509Certificate[certs.size()]);
}
Also used : ArrayList(java.util.ArrayList) CertificateException(java.security.cert.CertificateException) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) SignatureException(java.security.SignatureException) InvalidKeySpecException(java.security.spec.InvalidKeySpecException) BufferUnderflowException(java.nio.BufferUnderflowException) InvalidAlgorithmParameterException(java.security.InvalidAlgorithmParameterException) PublicKey(java.security.PublicKey) X509EncodedKeySpec(java.security.spec.X509EncodedKeySpec) IOException(java.io.IOException) InvalidKeyException(java.security.InvalidKeyException) DirectByteBuffer(java.nio.DirectByteBuffer) ByteBuffer(java.nio.ByteBuffer) X509Certificate(java.security.cert.X509Certificate) BigInteger(java.math.BigInteger) ByteArrayInputStream(java.io.ByteArrayInputStream) Signature(java.security.Signature) AlgorithmParameterSpec(java.security.spec.AlgorithmParameterSpec)

Example 39 with BufferUnderflowException

use of java.nio.BufferUnderflowException in project android_frameworks_base by DirtyUnicorns.

the class ApkSignatureSchemeV2Verifier method getByteBuffer.

/**
     * Relative <em>get</em> method for reading {@code size} number of bytes from the current
     * position of this buffer.
     *
     * <p>This method reads the next {@code size} bytes at this buffer's current position,
     * returning them as a {@code ByteBuffer} with start set to 0, limit and capacity set to
     * {@code size}, byte order set to this buffer's byte order; and then increments the position by
     * {@code size}.
     */
private static ByteBuffer getByteBuffer(ByteBuffer source, int size) throws BufferUnderflowException {
    if (size < 0) {
        throw new IllegalArgumentException("size: " + size);
    }
    int originalLimit = source.limit();
    int position = source.position();
    int limit = position + size;
    if ((limit < position) || (limit > originalLimit)) {
        throw new BufferUnderflowException();
    }
    source.limit(limit);
    try {
        ByteBuffer result = source.slice();
        result.order(source.order());
        source.position(limit);
        return result;
    } finally {
        source.limit(originalLimit);
    }
}
Also used : DirectByteBuffer(java.nio.DirectByteBuffer) ByteBuffer(java.nio.ByteBuffer) BufferUnderflowException(java.nio.BufferUnderflowException)

Example 40 with BufferUnderflowException

use of java.nio.BufferUnderflowException in project android_frameworks_base by AOSPA.

the class ApkSignatureSchemeV2Verifier method verifySigner.

private static X509Certificate[] verifySigner(ByteBuffer signerBlock, Map<Integer, byte[]> contentDigests, CertificateFactory certFactory) throws SecurityException, IOException {
    ByteBuffer signedData = getLengthPrefixedSlice(signerBlock);
    ByteBuffer signatures = getLengthPrefixedSlice(signerBlock);
    byte[] publicKeyBytes = readLengthPrefixedByteArray(signerBlock);
    int signatureCount = 0;
    int bestSigAlgorithm = -1;
    byte[] bestSigAlgorithmSignatureBytes = null;
    List<Integer> signaturesSigAlgorithms = new ArrayList<>();
    while (signatures.hasRemaining()) {
        signatureCount++;
        try {
            ByteBuffer signature = getLengthPrefixedSlice(signatures);
            if (signature.remaining() < 8) {
                throw new SecurityException("Signature record too short");
            }
            int sigAlgorithm = signature.getInt();
            signaturesSigAlgorithms.add(sigAlgorithm);
            if (!isSupportedSignatureAlgorithm(sigAlgorithm)) {
                continue;
            }
            if ((bestSigAlgorithm == -1) || (compareSignatureAlgorithm(sigAlgorithm, bestSigAlgorithm) > 0)) {
                bestSigAlgorithm = sigAlgorithm;
                bestSigAlgorithmSignatureBytes = readLengthPrefixedByteArray(signature);
            }
        } catch (IOException | BufferUnderflowException e) {
            throw new SecurityException("Failed to parse signature record #" + signatureCount, e);
        }
    }
    if (bestSigAlgorithm == -1) {
        if (signatureCount == 0) {
            throw new SecurityException("No signatures found");
        } else {
            throw new SecurityException("No supported signatures found");
        }
    }
    String keyAlgorithm = getSignatureAlgorithmJcaKeyAlgorithm(bestSigAlgorithm);
    Pair<String, ? extends AlgorithmParameterSpec> signatureAlgorithmParams = getSignatureAlgorithmJcaSignatureAlgorithm(bestSigAlgorithm);
    String jcaSignatureAlgorithm = signatureAlgorithmParams.first;
    AlgorithmParameterSpec jcaSignatureAlgorithmParams = signatureAlgorithmParams.second;
    boolean sigVerified;
    try {
        PublicKey publicKey = KeyFactory.getInstance(keyAlgorithm).generatePublic(new X509EncodedKeySpec(publicKeyBytes));
        Signature sig = Signature.getInstance(jcaSignatureAlgorithm);
        sig.initVerify(publicKey);
        if (jcaSignatureAlgorithmParams != null) {
            sig.setParameter(jcaSignatureAlgorithmParams);
        }
        sig.update(signedData);
        sigVerified = sig.verify(bestSigAlgorithmSignatureBytes);
    } catch (NoSuchAlgorithmException | InvalidKeySpecException | InvalidKeyException | InvalidAlgorithmParameterException | SignatureException e) {
        throw new SecurityException("Failed to verify " + jcaSignatureAlgorithm + " signature", e);
    }
    if (!sigVerified) {
        throw new SecurityException(jcaSignatureAlgorithm + " signature did not verify");
    }
    // Signature over signedData has verified.
    byte[] contentDigest = null;
    signedData.clear();
    ByteBuffer digests = getLengthPrefixedSlice(signedData);
    List<Integer> digestsSigAlgorithms = new ArrayList<>();
    int digestCount = 0;
    while (digests.hasRemaining()) {
        digestCount++;
        try {
            ByteBuffer digest = getLengthPrefixedSlice(digests);
            if (digest.remaining() < 8) {
                throw new IOException("Record too short");
            }
            int sigAlgorithm = digest.getInt();
            digestsSigAlgorithms.add(sigAlgorithm);
            if (sigAlgorithm == bestSigAlgorithm) {
                contentDigest = readLengthPrefixedByteArray(digest);
            }
        } catch (IOException | BufferUnderflowException e) {
            throw new IOException("Failed to parse digest record #" + digestCount, e);
        }
    }
    if (!signaturesSigAlgorithms.equals(digestsSigAlgorithms)) {
        throw new SecurityException("Signature algorithms don't match between digests and signatures records");
    }
    int digestAlgorithm = getSignatureAlgorithmContentDigestAlgorithm(bestSigAlgorithm);
    byte[] previousSignerDigest = contentDigests.put(digestAlgorithm, contentDigest);
    if ((previousSignerDigest != null) && (!MessageDigest.isEqual(previousSignerDigest, contentDigest))) {
        throw new SecurityException(getContentDigestAlgorithmJcaDigestAlgorithm(digestAlgorithm) + " contents digest does not match the digest specified by a preceding signer");
    }
    ByteBuffer certificates = getLengthPrefixedSlice(signedData);
    List<X509Certificate> certs = new ArrayList<>();
    int certificateCount = 0;
    while (certificates.hasRemaining()) {
        certificateCount++;
        byte[] encodedCert = readLengthPrefixedByteArray(certificates);
        X509Certificate certificate;
        try {
            certificate = (X509Certificate) certFactory.generateCertificate(new ByteArrayInputStream(encodedCert));
        } catch (CertificateException e) {
            throw new SecurityException("Failed to decode certificate #" + certificateCount, e);
        }
        certificate = new VerbatimX509Certificate(certificate, encodedCert);
        certs.add(certificate);
    }
    if (certs.isEmpty()) {
        throw new SecurityException("No certificates listed");
    }
    X509Certificate mainCertificate = certs.get(0);
    byte[] certificatePublicKeyBytes = mainCertificate.getPublicKey().getEncoded();
    if (!Arrays.equals(publicKeyBytes, certificatePublicKeyBytes)) {
        throw new SecurityException("Public key mismatch between certificate and signature record");
    }
    return certs.toArray(new X509Certificate[certs.size()]);
}
Also used : ArrayList(java.util.ArrayList) CertificateException(java.security.cert.CertificateException) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) SignatureException(java.security.SignatureException) InvalidKeySpecException(java.security.spec.InvalidKeySpecException) BufferUnderflowException(java.nio.BufferUnderflowException) InvalidAlgorithmParameterException(java.security.InvalidAlgorithmParameterException) PublicKey(java.security.PublicKey) X509EncodedKeySpec(java.security.spec.X509EncodedKeySpec) IOException(java.io.IOException) InvalidKeyException(java.security.InvalidKeyException) DirectByteBuffer(java.nio.DirectByteBuffer) ByteBuffer(java.nio.ByteBuffer) X509Certificate(java.security.cert.X509Certificate) BigInteger(java.math.BigInteger) ByteArrayInputStream(java.io.ByteArrayInputStream) Signature(java.security.Signature) AlgorithmParameterSpec(java.security.spec.AlgorithmParameterSpec)

Aggregations

BufferUnderflowException (java.nio.BufferUnderflowException)123 ByteBuffer (java.nio.ByteBuffer)70 IOException (java.io.IOException)25 ArrayList (java.util.ArrayList)22 DirectByteBuffer (java.nio.DirectByteBuffer)15 Test (org.junit.Test)14 CertificateException (java.security.cert.CertificateException)12 X509Certificate (java.security.cert.X509Certificate)11 BigInteger (java.math.BigInteger)10 ByteSource (org.apache.geode.internal.tcp.ByteBufferInputStream.ByteSource)9 IntegrationTest (org.apache.geode.test.junit.categories.IntegrationTest)9 SerializationTest (org.apache.geode.test.junit.categories.SerializationTest)9 UnitTest (org.apache.geode.test.junit.categories.UnitTest)9 CharBuffer (java.nio.CharBuffer)7 ByteArrayInputStream (java.io.ByteArrayInputStream)6 FloatBuffer (java.nio.FloatBuffer)6 CertificateFactory (java.security.cert.CertificateFactory)6 HashMap (java.util.HashMap)6 ArrayMap (android.util.ArrayMap)5 HSIconFileElement (com.android.anqp.HSIconFileElement)5