View Javadoc
1   /*
2    * The contents of this file are subject to the terms of the Common Development and
3    * Distribution License (the License). You may not use this file except in compliance with the
4    * License.
5    *
6    * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
7    * specific language governing permission and limitations under the License.
8    *
9    * When distributing Covered Software, include this CDDL Header Notice in each file and include
10   * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
11   * Header, with the fields enclosed by brackets [] replaced by your own identifying
12   * information: "Portions copyright [year] [name of copyright owner]".
13   *
14   * Copyright 2013-2016 ForgeRock AS.
15   */
16  
17  package org.forgerock.json.jose.jws;
18  
19  import org.forgerock.json.jose.jwe.CompressionManager;
20  import org.forgerock.json.jose.jws.handlers.SigningHandler;
21  import org.forgerock.json.jose.jwt.Jwt;
22  import org.forgerock.json.jose.jwt.JwtClaimsSet;
23  import org.forgerock.json.jose.jwt.Payload;
24  import org.forgerock.json.jose.utils.Utils;
25  import org.forgerock.util.encode.Base64url;
26  
27  /**
28   * A JWS implementation of the <tt>Jwt</tt> interface.
29   * <p>
30   * JSON Web Signature (JWS) is a means of representing content secured with digital signatures or Message
31   * Authentication Codes (MACs) using JSON based data structures.
32   * <p>
33   * @see <a href="http://tools.ietf.org/html/draft-ietf-jose-json-web-signature-11">JSON Web Signature Specification</a>
34   *
35   * @since 2.0.0
36   */
37  public class SignedJwt implements Jwt, Payload {
38  
39      private final JwsHeader header;
40      private final Payload payload;
41  
42      private final SigningHandler signingHandler;
43  
44      private final byte[] signingInput;
45      private final byte[] signature;
46  
47      /**
48       * Constructs a fresh, new SignedJwt from the given JwsHeader and JwtClaimsSet.
49       * <p>
50       * The specified private key will be used in the creation of the JWS signature.
51       *
52       * @param header The JwsHeader containing the header parameters of the JWS.
53       * @param claimsSet The JwtClaimsSet containing the claims of the JWS.
54       * @param signingHandler The SigningHandler instance used to sign the JWS.
55       */
56      public SignedJwt(JwsHeader header, JwtClaimsSet claimsSet, SigningHandler signingHandler) {
57          this.header = header;
58          this.payload = claimsSet;
59          this.signingHandler = signingHandler;
60  
61          this.signingInput = null;
62          this.signature = null;
63      }
64  
65      /**
66       * Constructs a reconstructed SignedJwt from its constituent parts, the JwsHeader, JwtClaimsSet, signing input and
67       * signature.
68       * <p>
69       * For use when a signed JWT has been reconstructed from its base64url encoded string representation and the
70       * signature needs verifying.
71       *
72       * @param header The JwsHeader containing the header parameters of the JWS.
73       * @param claimsSet The JwsClaimsSet containing the claims of the JWS.
74       * @param signingInput The original data that was signed, being the base64url encoding of the JWS header and
75       *                     claims set concatenated using a "." character.
76       * @param signature The resulting signature of signing the signing input.
77       */
78      public SignedJwt(JwsHeader header, JwtClaimsSet claimsSet, byte[] signingInput, byte[] signature) {
79          this.header = header;
80          this.payload = claimsSet;
81          this.signingInput = signingInput;
82          this.signature = signature;
83  
84          this.signingHandler = null;
85      }
86  
87      /**
88       * Constructs a fresh, new SignedJwt from the given JwsHeader and nested Encrypted JWT.
89       * <p>
90       * The specified private key will be used in the creation of the JWS signature.
91       *
92       * @param header The JwsHeader containing the header parameters of the JWS.
93       * @param nestedPayload The nested payload that will be the payload of this JWS.
94       * @param signingHandler The SigningHandler instance used to sign the JWS.
95       */
96      protected SignedJwt(JwsHeader header, Payload nestedPayload, SigningHandler signingHandler) {
97          this.header = header;
98          this.payload = nestedPayload;
99          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 }