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 }