CommonSEHeader.java

/*
 * nimbus-jose-jwt
 *
 * Copyright 2012-2016, Connect2id Ltd.
 *
 * 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 com.nimbusds.jose;


import java.net.URI;
import java.text.ParseException;
import java.util.*;

import com.nimbusds.jose.jwk.JWK;
import com.nimbusds.jose.util.Base64;
import com.nimbusds.jose.util.Base64URL;


/**
 * Common class for JWS and JWE headers.
 *
 * <p>Supports all registered header parameters shared by the JWS and JWE
 * specifications:
 *
 * <ul>
 *     <li>alg
 *     <li>jku
 *     <li>jwk
 *     <li>x5u
 *     <li>x5t
 *     <li>x5t#S256
 *     <li>x5c
 *     <li>kid
 *     <li>typ
 *     <li>cty
 *     <li>crit
 * </ul>
 *
 * @author Vladimir Dzhuvinov
 * @version 2022-03-07
 */
abstract class CommonSEHeader extends Header {


	private static final long serialVersionUID = 1L;


	/**
	 * Public JWK Set URL, {@code null} if not specified.
	 */
	private final URI jku;


	/**
	 * Public JWK, {@code null} if not specified.
	 */
	private final JWK jwk;


	/**
	 * X.509 certificate URL, {@code null} if not specified.
	 */
	private final URI x5u;


	/**
	 * X.509 certificate SHA-1 thumbprint, {@code null} if not specified.
	 */
	private final Base64URL x5t;


	/**
	 * X.509 certificate SHA-256 thumbprint, {@code null} if not specified.
	 */
	private final Base64URL x5t256;


	/**
	 * The X.509 certificate chain corresponding to the key used to sign or 
	 * encrypt the JWS / JWE object, {@code null} if not specified.
	 */
	private final List<Base64> x5c;


	/**
	 * Key ID, {@code null} if not specified.
	 */
	private final String kid;


	/**
	 * Creates a new common JWS and JWE header.
	 *
	 * @param alg             The algorithm ({@code alg}) parameter. Must
	 *                        not be {@code null}.
	 * @param typ             The type ({@code typ}) parameter,
	 *                        {@code null} if not specified.
	 * @param cty             The content type ({@code cty}) parameter,
	 *                        {@code null} if not specified.
	 * @param crit            The names of the critical header
	 *                        ({@code crit}) parameters, empty set or
	 *                        {@code null} if none.
	 * @param jku             The public JSON Web Key (JWK) Set URL
	 *                        ({@code jku}) parameter, {@code null} if not
	 *                        specified.
	 * @param jwk             The public JSON Web Key (JWK) ({@code jwk})
	 *                        parameter, {@code null} if not specified.
	 * @param x5u             The X.509 certificate URL parameter
	 *                        ({@code x5u}), {@code null} if not specified.
	 * @param x5t             The X.509 certificate SHA-1 thumbprint
	 *                        ({@code x5t}) parameter, {@code null} if not
	 *                        specified.
	 * @param x5t256          The X.509 certificate SHA-256 thumbprint
	 *                        ({@code x5t#S256}) parameter, {@code null} if
	 *                        not specified.
	 * @param x5c             The X.509 certificate chain ({@code x5c})
	 *                        parameter, {@code null} if not specified.
	 * @param kid             The key ID ({@code kid}) parameter,
	 *                        {@code null} if not specified.
	 * @param customParams    The custom parameters, empty map or
	 *                        {@code null} if none.
	 * @param parsedBase64URL The parsed Base64URL, {@code null} if the
	 *                        header is created from scratch.
	 */
	protected CommonSEHeader(final Algorithm alg,
				 final JOSEObjectType typ,
				 final String cty,
				 final Set<String> crit,
				 final URI jku,
				 final JWK jwk,
				 final URI x5u,
				 final Base64URL x5t,
				 final Base64URL x5t256,
				 final List<Base64> x5c,
				 final String kid,
				 final Map<String,Object> customParams,
				 final Base64URL parsedBase64URL) {

		super(alg, typ, cty, crit, customParams, parsedBase64URL);

		this.jku = jku;
		this.jwk = jwk;
		this.x5u = x5u;
		this.x5t = x5t;
		this.x5t256 = x5t256;

		if (x5c != null) {
			// Copy and make unmodifiable
			this.x5c = Collections.unmodifiableList(new ArrayList<>(x5c));
		} else {
			this.x5c = null;
		}

		this.kid = kid;
	}


	/**
	 * Gets the public JSON Web Key (JWK) Set URL ({@code jku}) parameter.
	 *
	 * @return The public JSON Web Key (JWK) Set URL parameter,
	 *         {@code null} if not specified.
	 */
	public URI getJWKURL() {

		return jku;
	}


	/**
	 * Gets the public JSON Web Key (JWK) ({@code jwk}) parameter.
	 *
	 * @return The public JSON Web Key (JWK) parameter, {@code null} if not
	 *         specified.
	 */
	public JWK getJWK() {

		return jwk;
	}


	/**
	 * Gets the X.509 certificate URL ({@code x5u}) parameter.
	 *
	 * @return The X.509 certificate URL parameter, {@code null} if not
	 *         specified.
	 */
	public URI getX509CertURL() {

		return x5u;
	}


	/**
	 * Gets the X.509 certificate SHA-1 thumbprint ({@code x5t}) parameter.
	 *
	 * @return The X.509 certificate SHA-1 thumbprint parameter,
	 *         {@code null} if not specified.
	 */
	@Deprecated
	public Base64URL getX509CertThumbprint() {

		return x5t;
	}


	/**
	 * Gets the X.509 certificate SHA-256 thumbprint ({@code x5t#S256})
	 * parameter.
	 *
	 * @return The X.509 certificate SHA-256 thumbprint parameter,
	 *         {@code null} if not specified.
	 */
	public Base64URL getX509CertSHA256Thumbprint() {

		return x5t256;
	}


	/**
	 * Gets the X.509 certificate chain ({@code x5c}) parameter
	 * corresponding to the key used to sign or encrypt the JWS / JWE
	 * object.
	 *
	 * @return The X.509 certificate chain parameter as a unmodifiable
	 *         list, {@code null} if not specified.
	 */
	public List<Base64> getX509CertChain() {

		return x5c;
	}


	/**
	 * Gets the key ID ({@code kid}) parameter.
	 *
	 * @return The key ID parameter, {@code null} if not specified.
	 */
	public String getKeyID() {

		return kid;
	}


	@Override
	public Set<String> getIncludedParams() {

		Set<String> includedParameters = super.getIncludedParams();

		if (jku != null) {
			includedParameters.add(HeaderParameterNames.JWK_SET_URL);
		}

		if (jwk != null) {
			includedParameters.add(HeaderParameterNames.JWK);
		}

		if (x5u != null) {
			includedParameters.add(HeaderParameterNames.X_509_CERT_URL);
		}

		if (x5t != null) {
			includedParameters.add(HeaderParameterNames.X_509_CERT_SHA_1_THUMBPRINT);
		}

		if (x5t256 != null) {
			includedParameters.add(HeaderParameterNames.X_509_CERT_SHA_256_THUMBPRINT);
		}

		if (x5c != null && ! x5c.isEmpty()) {
			includedParameters.add(HeaderParameterNames.X_509_CERT_CHAIN);
		}

		if (kid != null) {
			includedParameters.add(HeaderParameterNames.KEY_ID);
		}

		return includedParameters;
	}


	@Override
	public Map<String, Object> toJSONObject() {

		Map<String, Object> o = super.toJSONObject();

		if (jku != null) {
			o.put(HeaderParameterNames.JWK_SET_URL, jku.toString());
		}

		if (jwk != null) {
			o.put(HeaderParameterNames.JWK, jwk.toJSONObject());
		}

		if (x5u != null) {
			o.put(HeaderParameterNames.X_509_CERT_URL, x5u.toString());
		}

		if (x5t != null) {
			o.put(HeaderParameterNames.X_509_CERT_SHA_1_THUMBPRINT, x5t.toString());
		}

		if (x5t256 != null) {
			o.put(HeaderParameterNames.X_509_CERT_SHA_256_THUMBPRINT, x5t256.toString());
		}

		if (x5c != null && ! x5c.isEmpty()) {
			List<String> x5cJson = new ArrayList<>(x5c.size());
			for (Base64 item : x5c) {
			    x5cJson.add(item.toString());
			}
			o.put(HeaderParameterNames.X_509_CERT_CHAIN, x5cJson);
		}

		if (kid != null) {
			o.put(HeaderParameterNames.KEY_ID, kid);
		}

		return o;
	}
	
	
	/**
	 * Parses a public JWK.
	 *
	 * @param jwkObject The JWK object in a JWS or JWE header, {@code null}
	 *                  if not specified.
	 *
	 * @return The JWK, {@code null} if none.
	 *
	 * @throws ParseException If public JWK parsing failed.
	 */
	static JWK parsePublicJWK(final Map<String, Object> jwkObject)
		throws ParseException {
		
		if (jwkObject == null) {
			return null;
		}
		
		JWK jwk = JWK.parse(jwkObject);
		
		if (jwk.isPrivate()) {
			throw new ParseException("Non-public key in jwk header parameter", 0);
		}
		
		return jwk;
	}
}