org.echocat.marquardt.common.Validator.java Source code

Java tutorial

Introduction

Here is the source code for org.echocat.marquardt.common.Validator.java

Source

/*
 * echocat Marquardt Java SDK, Copyright (c) 2015 echocat
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

package org.echocat.marquardt.common;

import com.google.common.base.Function;
import com.google.common.io.CountingInputStream;
import org.apache.commons.io.IOUtils;
import org.echocat.marquardt.common.domain.DeserializingFactory;
import org.echocat.marquardt.common.domain.Signable;
import org.echocat.marquardt.common.domain.Signature;
import org.echocat.marquardt.common.exceptions.SignatureValidationFailedException;
import org.echocat.marquardt.common.util.InputStreamUtils;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.security.PublicKey;

/**
 * Validates and deserializes signed Signables.
 *
 * @see Signature
 * @see Signable
 * @see Signer
 */
public class Validator {

    /**
     * Deserializes and validates signed Signables.
     *
     * @param content Serialized Signable including Signature.
     * @param signableDeserializingFactory Factory to deserialize Signable with.
     * @param publicKeyProvider to return matching public key for given signable.
     * @param <T> Type of your Signable. Also Certificate uses this.
     * @return Deserialized and validated Signable.
     *
     * @throws SignatureValidationFailedException If the signature cannot be read or no key is provided to check.
     * @throws IllegalArgumentException when Signable cannot be deserialized from content using the provided factory or
     * no Signature can be extracted from provided content.
     */
    @Nonnull
    public <T extends Signable> T deserializeAndValidate(final byte[] content,
            final DeserializingFactory<T> signableDeserializingFactory,
            final Function<T, PublicKey> publicKeyProvider) {
        final ByteArrayInputStream inputStream = new ByteArrayInputStream(content);
        try {
            final CountingInputStream bufferedInputStream = new CountingInputStream(inputStream);
            try {
                bufferedInputStream.mark(0);
                final T signable = signableDeserializingFactory.consume(bufferedInputStream);

                final byte[] signableBytes = readSignableBytesAgainForLaterValidation(bufferedInputStream);

                final PublicKey publicKey = publicKeyProvider.apply(signable);
                if (publicKey == null) {
                    throw new SignatureValidationFailedException("no public key provided");
                }
                final int signatureLength = InputStreamUtils.readInt(bufferedInputStream);
                final Signature signature = new Signature(
                        InputStreamUtils.readBytes(bufferedInputStream, signatureLength));
                if (signature.isValidFor(signableBytes, publicKey)) {
                    return signable;
                }
                throw new SignatureValidationFailedException("signature is invalid for provided public key");
            } finally {
                IOUtils.closeQuietly(bufferedInputStream);
            }
        } catch (final IOException e) {
            throw new IllegalArgumentException("Signable cannot be deserialized using "
                    + signableDeserializingFactory.getClass() + " or content is wrong / contains no signature.", e);
        } finally {
            IOUtils.closeQuietly(inputStream);
        }
    }

    /**
     * Convenience method with signable independent public key to deserializes and validates signed Signables.
     *
     * @param content Serialized Signable including Signature.
     * @param signableDeserializingFactory Factory to deserialize Signable with.
     * @param publicKey to return.
     * @param <T> Type of your Signable. Also Certificate uses this.
     * @return Deserialized and validated Signable.
     *
     * @throws SignatureValidationFailedException If the signature cannot be read or no key is provided to check.
     * @throws IllegalArgumentException when Signable cannot be deserialized from content using the provided factory or
     * no Signature can be extracted from provided content.
     */
    public <T extends Signable> T deserializeAndValidate(final byte[] content,
            final DeserializingFactory<T> signableDeserializingFactory, final PublicKey publicKey) {
        return deserializeAndValidate(content, signableDeserializingFactory, new Function<T, PublicKey>() {
            @Nullable
            @Override
            public PublicKey apply(final T t) {
                return publicKey;
            }
        });
    }

    private byte[] readSignableBytesAgainForLaterValidation(final CountingInputStream bufferedInputStream)
            throws IOException {
        final int position = (int) bufferedInputStream.getCount();
        bufferedInputStream.reset();
        final byte[] bytes = new byte[position];
        IOUtils.read(bufferedInputStream, bytes, 0, position);
        return bytes;
    }
}