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