SignedThenEncryptedJwt.java

/*
 * The contents of this file are subject to the terms of the Common Development and
 * Distribution License (the License). You may not use this file except in compliance with the
 * License.
 *
 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
 * specific language governing permission and limitations under the License.
 *
 * When distributing Covered Software, include this CDDL Header Notice in each file and include
 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
 * Header, with the fields enclosed by brackets [] replaced by your own identifying
 * information: "Portions copyright [year] [name of copyright owner]".
 *
 * Copyright 2016 ForgeRock AS.
 */

package org.forgerock.json.jose.jwe;

import java.security.Key;

import org.forgerock.json.jose.common.JwtReconstruction;
import org.forgerock.json.jose.exceptions.JweDecryptionException;
import org.forgerock.json.jose.exceptions.JwsVerifyingException;
import org.forgerock.json.jose.jws.SignedJwt;
import org.forgerock.json.jose.jws.handlers.SigningHandler;
import org.forgerock.json.jose.jwt.JwtClaimsSet;
import org.forgerock.json.jose.jwt.Payload;

/**
 * A nested signed-then-encrypted JWT.
 */
public class SignedThenEncryptedJwt extends EncryptedJwt {
    private static final JwtReconstruction JWT_RECONSTRUCTION = new JwtReconstruction();

    /**
     * Constructs a fresh signed-then-encrypted JWT with the given signed JWT payload, JWE headers and encryption key.
     *
     * @param header the JWE headers.
     * @param payload the signed JWT payload.
     * @param publicKey the encryption key.
     */
    public SignedThenEncryptedJwt(final JweHeader header, final SignedJwt payload, final Key publicKey) {
        super(header, payload, publicKey);
    }

    /**
     * Reconstructs a signed-then-encrypted JWT from components parts of the encrypted JWT string.
     *
     * @param header the decoded headers.
     * @param encodedHeader the encoded headers.
     * @param encryptedContentEncryptionKey the encrypted content encryption key (CEK), or null if not used.
     * @param initialisationVector the initialisation vector (IV).
     * @param ciphertext the encrypted ciphertext payload.
     * @param authenticationTag the authentication MAC tag.
     */
    public SignedThenEncryptedJwt(final JweHeader header, final String encodedHeader,
            final byte[] encryptedContentEncryptionKey,
            final byte[] initialisationVector, final byte[] ciphertext, final byte[] authenticationTag) {
        super(header, encodedHeader, encryptedContentEncryptionKey, initialisationVector, ciphertext,
                authenticationTag);
    }

    /**
     * Verifies that the signature is valid on the nested signed JWT.
     * @param signingHandler the handler to use for verifying the signature.
     * @return {@literal true} if the signature is valid, otherwise {@literal false}.
     * @throws JwsVerifyingException if the outer JWT has not already been decrypted.
     */
    public boolean verify(SigningHandler signingHandler) {
        if (getPayload() == null) {
            throw new JwsVerifyingException("JWT must be decrypted before the nested signature can be verified");
        }
        return ((SignedJwt) getPayload()).verify(signingHandler);
    }

    /**
     * Decrypts the outer JWT and then verifies the signature on the inner JWT.
     *
     * @param decryptionKey the decryption key for the outer JWE.
     * @param signingHandler the signing handler for verifying the nested JWS.
     * @return {@literal true} if the nested signature is valid, otherwise {@literal false}.
     * @throws JweDecryptionException if the JWE cannot be decrypted.
     */
    public boolean decryptAndVerify(Key decryptionKey, SigningHandler signingHandler) {
        decrypt(decryptionKey);
        return verify(signingHandler);
    }

    @Override
    public JwtClaimsSet getClaimsSet() {
        return ((SignedJwt) getPayload()).getClaimsSet();
    }


    @Override
    Payload decodePayload(String decryptedPayload) {
        return JWT_RECONSTRUCTION.reconstructJwt(decryptedPayload, SignedJwt.class);
    }
}