001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2016 ForgeRock AS. 015 */ 016 017package org.forgerock.json.jose.jwe; 018 019import java.security.Key; 020 021import org.forgerock.json.jose.common.JwtReconstruction; 022import org.forgerock.json.jose.exceptions.JweDecryptionException; 023import org.forgerock.json.jose.exceptions.JwsVerifyingException; 024import org.forgerock.json.jose.jws.SignedJwt; 025import org.forgerock.json.jose.jws.handlers.SigningHandler; 026import org.forgerock.json.jose.jwt.JwtClaimsSet; 027import org.forgerock.json.jose.jwt.Payload; 028 029/** 030 * A nested signed-then-encrypted JWT. 031 */ 032public class SignedThenEncryptedJwt extends EncryptedJwt { 033 private static final JwtReconstruction JWT_RECONSTRUCTION = new JwtReconstruction(); 034 035 /** 036 * Constructs a fresh signed-then-encrypted JWT with the given signed JWT payload, JWE headers and encryption key. 037 * 038 * @param header the JWE headers. 039 * @param payload the signed JWT payload. 040 * @param publicKey the encryption key. 041 */ 042 public SignedThenEncryptedJwt(final JweHeader header, final SignedJwt payload, final Key publicKey) { 043 super(header, payload, publicKey); 044 } 045 046 /** 047 * Reconstructs a signed-then-encrypted JWT from components parts of the encrypted JWT string. 048 * 049 * @param header the decoded headers. 050 * @param encodedHeader the encoded headers. 051 * @param encryptedContentEncryptionKey the encrypted content encryption key (CEK), or null if not used. 052 * @param initialisationVector the initialisation vector (IV). 053 * @param ciphertext the encrypted ciphertext payload. 054 * @param authenticationTag the authentication MAC tag. 055 */ 056 public SignedThenEncryptedJwt(final JweHeader header, final String encodedHeader, 057 final byte[] encryptedContentEncryptionKey, 058 final byte[] initialisationVector, final byte[] ciphertext, final byte[] authenticationTag) { 059 super(header, encodedHeader, encryptedContentEncryptionKey, initialisationVector, ciphertext, 060 authenticationTag); 061 } 062 063 /** 064 * Verifies that the signature is valid on the nested signed JWT. 065 * @param signingHandler the handler to use for verifying the signature. 066 * @return {@literal true} if the signature is valid, otherwise {@literal false}. 067 * @throws JwsVerifyingException if the outer JWT has not already been decrypted. 068 */ 069 public boolean verify(SigningHandler signingHandler) { 070 if (getPayload() == null) { 071 throw new JwsVerifyingException("JWT must be decrypted before the nested signature can be verified"); 072 } 073 return ((SignedJwt) getPayload()).verify(signingHandler); 074 } 075 076 /** 077 * Decrypts the outer JWT and then verifies the signature on the inner JWT. 078 * 079 * @param decryptionKey the decryption key for the outer JWE. 080 * @param signingHandler the signing handler for verifying the nested JWS. 081 * @return {@literal true} if the nested signature is valid, otherwise {@literal false}. 082 * @throws JweDecryptionException if the JWE cannot be decrypted. 083 */ 084 public boolean decryptAndVerify(Key decryptionKey, SigningHandler signingHandler) { 085 decrypt(decryptionKey); 086 return verify(signingHandler); 087 } 088 089 @Override 090 public JwtClaimsSet getClaimsSet() { 091 return ((SignedJwt) getPayload()).getClaimsSet(); 092 } 093 094 095 @Override 096 Payload decodePayload(String decryptedPayload) { 097 return JWT_RECONSTRUCTION.reconstructJwt(decryptedPayload, SignedJwt.class); 098 } 099}