/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.cxf.rs.security.jose.jws; import java.util.ArrayList; import java.util.List; import org.apache.cxf.rs.security.jose.jwa.SignatureAlgorithm; import org.junit.Assert; import org.junit.Test; public class JwsCompactHeaderTest extends Assert { /** * JWS string, which lacks the "alg" header field. * * => Must be rejected by verification operation, since the spec declares * that the "alg" header field must be present in the compact serialization. */ public static final String MISSING_ALG_HEADER_FIELD_IN_JWS = "eyAiZ2xhIiA6ICJDQU1IIiB9.eyAibXNnIjogIllvdSBjYW4ndCB0b3VjaCB0aGlzISIgfQ" + ".Sqd_AuwlPPqv4L1EV4zPuR-HfFJpe9kOfvc597RlcoE"; /** * JWS string, which contains two "alg" header fields. Bogus "alg" header * field first. * * => Must be rejected by verification operation, since the spec declares * that the "alg" header field must be present once in the compact * serialization. */ public static final String TWO_ALG_HEADER_FIELDS_IN_JWS_BOGUS_FIRST = "eyAiYWxnIjogIkJvZ3VzIiwgImFsZyI6ICJIUzI1NiIgfQ.eyAibXNnIjogIllvdSBjYW4ndCB0b3VjaCB0aGlzISIgfQ" + ".FIgpDi1Wp9iIxxXfBw8Zce2kiZ8gmqAaVYPduRFR8kU"; /** * JWS string, which contains two "alg" header fields. Bogus "alg" header * field last. * * => Must be rejected by verification operation, since the spec declares * that the "alg" header field must be present once in the compact * serialization. */ public static final String TWO_ALG_HEADER_FIELDS_IN_JWS_BOGUS_LAST = "eyAiYWxnIjogIkhTMjU2IiwgImFsZyI6ICJCb2d1cyIgfQ.eyAibXNnIjogIllvdSBjYW4ndCB0b3VjaCB0aGlzISIgfQ" + ".Ftwla-nAg0Nty8ILVhjlIETOy2Tw1JsD3bBq55AS0PU"; /** * JWS string, which contains an invalid "alg" header field value. * * (1): Algorithm not supported/known * * => Must be rejected by verification operation, since the spec declares * that the signature is not valid if the "alg" value does not represent a * supported algorithm. "alg" values should either be registered in the IANA * JSON Web Signature and Encryption Algorithms registry defined in JWA or * be a value that contains a Collision-Resistant Name. */ public static final String INVALID_ALG_HEADER_VALUE_IN_JWS_1 = "tba"; /** * JWS string, which contains an invalid "alg" header field value. * * (2): Wrong value encoding * * => Must be rejected by verification operation, since the spec declares * that the "alg" value is a case-sensitive string containing a StringOrURI * value. */ public static final String INVALID_ALG_HEADER_VALUE_IN_JWS_2 = "tba"; /** * JWS string, which contains a "alg" header field value of "none". The * signature has been generated with "HS256" and the signed JWS has been * altered afterwards to the value "none". * * => Must be rejected by verification operation, since the "none" algorithm * is considered harmful. */ public static final String ALG_HEADER_VALUE_HS256_IN_JWS = "eyAiYWxnIjogIkhTMjU2IiB9" + ".eyAibXNnIjogIllvdSBjYW4ndCB0b3VjaCB0aGlzISIgfQ" + ".as_gclokwAmukh3zVF1X5sUCCfSc8TbjDdhdvk6C5c8"; public static final String ALG_HEADER_VALUE_NONE_IN_JWS = "eyAiYWxnIjogIm5vbmUiIH0" + ".eyAibXNnIjogIllvdSBjYW4ndCB0b3VjaCB0aGlzISIgfQ" + ".as_gclokwAmukh3zVF1X5sUCCfSc8TbjDdhdvk6C5c8"; /** * Support material (keys, etc.) */ private static final String ENCODED_MAC_KEY = "AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75" + "aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow"; // JWS string, which contains crit header field // JWS string, which contains more than three parts // JWS string, which contains less than three parts // JWS string, which contains null bytes padding @Test public void verifyJwsWithMissingAlgHeaderField() throws Exception { JwsCompactConsumer jwsConsumer = new JwsCompactConsumer(MISSING_ALG_HEADER_FIELD_IN_JWS); assertFalse(jwsConsumer.verifySignatureWith(new HmacJwsSignatureVerifier(ENCODED_MAC_KEY, SignatureAlgorithm.HS256))); } @Test public void verifyJwsWithTwoAlgHeaderFieldsBogusFieldFirst() throws Exception { JwsCompactConsumer jwsConsumer = new JwsCompactConsumer(TWO_ALG_HEADER_FIELDS_IN_JWS_BOGUS_FIRST); boolean result = jwsConsumer.verifySignatureWith(new HmacJwsSignatureVerifier(ENCODED_MAC_KEY, SignatureAlgorithm.HS256)); assertFalse(result); } @Test public void verifyJwsWithTwoAlgHeaderFieldsBogusFieldLast() throws Exception { JwsCompactConsumer jwsConsumer = new JwsCompactConsumer(TWO_ALG_HEADER_FIELDS_IN_JWS_BOGUS_LAST); assertFalse(jwsConsumer.verifySignatureWith(new HmacJwsSignatureVerifier(ENCODED_MAC_KEY, SignatureAlgorithm.HS256))); } @Test public void verifyJwsWithAlgHeaderValueNone() throws Exception { JwsCompactConsumer jwsConsumerOriginal = new JwsCompactConsumer(ALG_HEADER_VALUE_HS256_IN_JWS); JwsCompactConsumer jwsConsumerAltered = new JwsCompactConsumer(ALG_HEADER_VALUE_NONE_IN_JWS); assertTrue(jwsConsumerOriginal.verifySignatureWith(new HmacJwsSignatureVerifier(ENCODED_MAC_KEY, SignatureAlgorithm.HS256))); assertFalse(jwsConsumerAltered.verifySignatureWith(new HmacJwsSignatureVerifier(ENCODED_MAC_KEY, SignatureAlgorithm.HS256))); } @Test public void testCriticalHeader() { String payload = "this is a JWS with critical header"; String criticalParameter = "criticalParameter"; String criticalParameter1 = "criticalParameter1"; String criticalParameter2 = "criticalParameter2"; String criticalParameter3 = "criticalParameter3"; String criticalValue = "criticalValue"; String criticalValue1 = "criticalValue1"; String criticalValue2 = "criticalValue2"; String criticalValue3 = "criticalValue3"; JwsCompactProducer producer = new JwsCompactProducer(payload); producer.getJwsHeaders().setSignatureAlgorithm(SignatureAlgorithm.HS512); List<String> criticalHeader = new ArrayList<>(); criticalHeader.add(criticalParameter1); producer.getJwsHeaders().setCritical(criticalHeader); producer.signWith(new HmacJwsSignatureProvider(ENCODED_MAC_KEY, SignatureAlgorithm.HS256)); String signedJws = producer.getSignedEncodedJws(); JwsCompactConsumer consumer = new JwsCompactConsumer(signedJws); assertFalse(consumer.validateCriticalHeaders()); criticalHeader.add(criticalParameter2); criticalHeader.add(criticalParameter3); producer = new JwsCompactProducer(payload); producer.getJwsHeaders().setSignatureAlgorithm(SignatureAlgorithm.HS512); producer.getJwsHeaders().setCritical(criticalHeader); producer.getJwsHeaders().setHeader(criticalParameter1, criticalValue1); producer.getJwsHeaders().setHeader(criticalParameter2, criticalValue2); producer.getJwsHeaders().setHeader(criticalParameter3, criticalValue3); producer.signWith(new HmacJwsSignatureProvider(ENCODED_MAC_KEY, SignatureAlgorithm.HS256)); signedJws = producer.getSignedEncodedJws(); consumer = new JwsCompactConsumer(signedJws); assertTrue(consumer.validateCriticalHeaders()); criticalHeader = new ArrayList<>(); criticalHeader.add(criticalParameter); criticalHeader.add(criticalParameter); producer = new JwsCompactProducer(payload); producer.getJwsHeaders().setSignatureAlgorithm(SignatureAlgorithm.HS512); producer.getJwsHeaders().setHeader(criticalParameter, criticalValue); producer.getJwsHeaders().setCritical(criticalHeader); producer.signWith(new HmacJwsSignatureProvider(ENCODED_MAC_KEY, SignatureAlgorithm.HS256)); signedJws = producer.getSignedEncodedJws(); consumer = new JwsCompactConsumer(signedJws); assertFalse(consumer.validateCriticalHeaders()); } }