All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.jsonwebtoken.impl.security.X509BuilderSupport Maven / Gradle / Ivy

There is a newer version: 0.12.6
Show newest version
/*
 * Copyright (C) 2021 jsonwebtoken.io
 *
 * Licensed 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 io.jsonwebtoken.impl.security;

import io.jsonwebtoken.impl.ParameterMap;
import io.jsonwebtoken.impl.io.Streams;
import io.jsonwebtoken.impl.lang.CheckedFunction;
import io.jsonwebtoken.impl.lang.Function;
import io.jsonwebtoken.impl.lang.Functions;
import io.jsonwebtoken.lang.Assert;
import io.jsonwebtoken.lang.Collections;
import io.jsonwebtoken.lang.Objects;
import io.jsonwebtoken.security.HashAlgorithm;
import io.jsonwebtoken.security.Jwks;
import io.jsonwebtoken.security.Request;
import io.jsonwebtoken.security.X509Builder;

import java.io.InputStream;
import java.net.URI;
import java.security.cert.X509Certificate;
import java.util.List;

//Consolidates logic between DefaultJwtHeaderBuilder and AbstractAsymmetricJwkBuilder
public class X509BuilderSupport implements X509Builder {

    private final ParameterMap map;

    protected boolean computeX509Sha1Thumbprint;

    /**
     * Boolean object indicates 3 states: 1) not configured 2) configured as true, 3) configured as false
     */
    protected Boolean computeX509Sha256Thumbprint = null;

    private static Function createGetBytesFunction(Class clazz) {
        return Functions.wrapFmt(new CheckedFunction() {
            @Override
            public byte[] apply(X509Certificate cert) throws Exception {
                return cert.getEncoded();
            }
        }, clazz, "Unable to access X509Certificate encoded bytes necessary to compute thumbprint. Certificate: %s");
    }

    private final Function GET_X509_BYTES;

    public X509BuilderSupport(ParameterMap map, Class getBytesFailedException) {
        this.map = Assert.notNull(map, "ParameterMap cannot be null.");
        this.GET_X509_BYTES = createGetBytesFunction(getBytesFailedException);
    }

    @Override
    public X509BuilderSupport x509Url(URI uri) {
        this.map.put(AbstractAsymmetricJwk.X5U.getId(), uri);
        return this;
    }

    @Override
    public X509BuilderSupport x509Chain(List chain) {
        this.map.put(AbstractAsymmetricJwk.X5C.getId(), chain);
        return this;
    }

    @Override
    public X509BuilderSupport x509Sha1Thumbprint(byte[] thumbprint) {
        this.map.put(AbstractAsymmetricJwk.X5T.getId(), thumbprint);
        return this;
    }

    @Override
    public X509BuilderSupport x509Sha1Thumbprint(boolean enable) {
        this.computeX509Sha1Thumbprint = enable;
        return this;
    }

    @Override
    public X509BuilderSupport x509Sha256Thumbprint(byte[] thumbprint) {
        this.map.put(AbstractAsymmetricJwk.X5T_S256.getId(), thumbprint);
        return this;
    }

    @Override
    public X509BuilderSupport x509Sha256Thumbprint(boolean enable) {
        this.computeX509Sha256Thumbprint = enable;
        return this;
    }

    private byte[] computeThumbprint(final X509Certificate cert, HashAlgorithm alg) {
        byte[] encoded = GET_X509_BYTES.apply(cert);
        InputStream in = Streams.of(encoded);
        Request request = new DefaultRequest<>(in, null, null);
        return alg.digest(request);
    }

    public void apply() {
        List chain = this.map.get(AbstractAsymmetricJwk.X5C);
        X509Certificate firstCert = null;
        if (!Collections.isEmpty(chain)) {
            firstCert = chain.get(0);
        }

        Boolean computeX509Sha256 = this.computeX509Sha256Thumbprint;
        if (computeX509Sha256 == null) { //if not specified, enable by default if possible:
            computeX509Sha256 = firstCert != null &&
                    !computeX509Sha1Thumbprint && // no need if at least one thumbprint will be set
                    Objects.isEmpty(this.map.get(AbstractAsymmetricJwk.X5T_S256)); // no need if already set
        }

        if (firstCert != null) {
            if (computeX509Sha1Thumbprint) {
                byte[] thumbprint = computeThumbprint(firstCert, DefaultHashAlgorithm.SHA1);
                x509Sha1Thumbprint(thumbprint);
            }
            if (computeX509Sha256) {
                byte[] thumbprint = computeThumbprint(firstCert, Jwks.HASH.SHA256);
                x509Sha256Thumbprint(thumbprint);
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy