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 }