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 2013-2016 ForgeRock AS.
015 */
016
017package org.forgerock.json.jose.jws;
018
019import org.forgerock.json.jose.jwe.CompressionManager;
020import org.forgerock.json.jose.jws.handlers.SigningHandler;
021import org.forgerock.json.jose.jwt.Jwt;
022import org.forgerock.json.jose.jwt.JwtClaimsSet;
023import org.forgerock.json.jose.jwt.Payload;
024import org.forgerock.json.jose.utils.Utils;
025import org.forgerock.util.encode.Base64url;
026
027/**
028 * A JWS implementation of the <tt>Jwt</tt> interface.
029 * <p>
030 * JSON Web Signature (JWS) is a means of representing content secured with digital signatures or Message
031 * Authentication Codes (MACs) using JSON based data structures.
032 * <p>
033 * @see <a href="http://tools.ietf.org/html/draft-ietf-jose-json-web-signature-11">JSON Web Signature Specification</a>
034 *
035 * @since 2.0.0
036 */
037public class SignedJwt implements Jwt, Payload {
038
039    private final JwsHeader header;
040    private final Payload payload;
041
042    private final SigningHandler signingHandler;
043
044    private final byte[] signingInput;
045    private final byte[] signature;
046
047    /**
048     * Constructs a fresh, new SignedJwt from the given JwsHeader and JwtClaimsSet.
049     * <p>
050     * The specified private key will be used in the creation of the JWS signature.
051     *
052     * @param header The JwsHeader containing the header parameters of the JWS.
053     * @param claimsSet The JwtClaimsSet containing the claims of the JWS.
054     * @param signingHandler The SigningHandler instance used to sign the JWS.
055     */
056    public SignedJwt(JwsHeader header, JwtClaimsSet claimsSet, SigningHandler signingHandler) {
057        this.header = header;
058        this.payload = claimsSet;
059        this.signingHandler = signingHandler;
060
061        this.signingInput = null;
062        this.signature = null;
063    }
064
065    /**
066     * Constructs a reconstructed SignedJwt from its constituent parts, the JwsHeader, JwtClaimsSet, signing input and
067     * signature.
068     * <p>
069     * For use when a signed JWT has been reconstructed from its base64url encoded string representation and the
070     * signature needs verifying.
071     *
072     * @param header The JwsHeader containing the header parameters of the JWS.
073     * @param claimsSet The JwsClaimsSet containing the claims of the JWS.
074     * @param signingInput The original data that was signed, being the base64url encoding of the JWS header and
075     *                     claims set concatenated using a "." character.
076     * @param signature The resulting signature of signing the signing input.
077     */
078    public SignedJwt(JwsHeader header, JwtClaimsSet claimsSet, byte[] signingInput, byte[] signature) {
079        this.header = header;
080        this.payload = claimsSet;
081        this.signingInput = signingInput;
082        this.signature = signature;
083
084        this.signingHandler = null;
085    }
086
087    /**
088     * Constructs a fresh, new SignedJwt from the given JwsHeader and nested Encrypted JWT.
089     * <p>
090     * The specified private key will be used in the creation of the JWS signature.
091     *
092     * @param header The JwsHeader containing the header parameters of the JWS.
093     * @param nestedPayload The nested payload that will be the payload of this JWS.
094     * @param signingHandler The SigningHandler instance used to sign the JWS.
095     */
096    protected SignedJwt(JwsHeader header, Payload nestedPayload, SigningHandler signingHandler) {
097        this.header = header;
098        this.payload = nestedPayload;
099        this.signingHandler = signingHandler;
100
101        this.signingInput = null;
102        this.signature = null;
103    }
104
105    /**
106     * Constructs a reconstructed SignedJwt from its constituent parts, the JwsHeader, nested Encrypted JWT, signing
107     * input and signature.
108     * <p>
109     * For use when a signed nested encrypted JWT has been reconstructed from its base64url encoded string
110     * representation and the signature needs verifying.
111     *
112     * @param header The JwsHeader containing the header parameters of the JWS.
113     * @param nestedPayload The nested payload that is the payload of the JWS.
114     * @param signingInput The original data that was signed, being the base64url encoding of the JWS header and
115     *                     payload concatenated using a "." character.
116     * @param signature The resulting signature of signing the signing input.
117     */
118    protected SignedJwt(JwsHeader header, Payload nestedPayload, byte[] signingInput, byte[] signature) {
119        this.header = header;
120        this.payload = nestedPayload;
121        this.signingInput = signingInput;
122        this.signature = signature;
123
124        this.signingHandler = null;
125    }
126
127    /**
128     * {@inheritDoc}
129     */
130    @Override
131    public JwsHeader getHeader() {
132        return header;
133    }
134
135    /**
136     * {@inheritDoc}
137     */
138    @Override
139    public JwtClaimsSet getClaimsSet() {
140        return (JwtClaimsSet) payload;
141    }
142
143    /**
144     * Gets the payload for the JWS, which will either be a JWT Claims Set, {@link #getClaimsSet()}, or a nested
145     * EncryptedJwt, {@link org.forgerock.json.jose.jwe.EncryptedJwt}.
146     *
147     * @return The JWS' payload.
148     * @see EncryptedThenSignedJwt
149     */
150    protected Payload getPayload() {
151        return payload;
152    }
153
154    /**
155     * {@inheritDoc}
156     */
157    @Override
158    public String build() {
159
160        String jwsHeader = header.build();
161        String encodedHeader = Utils.base64urlEncode(jwsHeader);
162        String jwsPayload = payload.build();
163
164        String encodedClaims = new CompressionManager().compress(header.getCompressionAlgorithm(), jwsPayload);
165
166        String signingInput = encodedHeader + "." + encodedClaims;
167
168        byte[] signature = signingHandler.sign(header.getAlgorithm(), signingInput);
169
170        return signingInput + "." + Base64url.encode(signature);
171    }
172
173    /**
174     * Verifies that the JWS signature is valid for the contents of its payload.
175     * <p>
176     * The same private key must be given here as was used to create the signature.
177     *
178     * @param signingHandler The SigningHandler instance used to verify the JWS.
179     * @return <code>true</code> if the signature matches the JWS Header and payload.
180     */
181    public boolean verify(SigningHandler signingHandler) {
182        return signingHandler.verify(header.getAlgorithm(), signingInput, signature);
183    }
184}