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}