001/* 002 * nimbus-jose-jwt 003 * 004 * Copyright 2012-2018, Connect2id Ltd. 005 * 006 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use 007 * this file except in compliance with the License. You may obtain a copy of the 008 * License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software distributed 013 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 014 * CONDITIONS OF ANY KIND, either express or implied. See the License for the 015 * specific language governing permissions and limitations under the License. 016 */ 017 018package com.nimbusds.jose.crypto; 019 020 021import java.security.GeneralSecurityException; 022import java.util.Set; 023 024import com.google.crypto.tink.subtle.Ed25519Verify; 025import com.nimbusds.jose.*; 026import com.nimbusds.jose.jwk.Curve; 027import com.nimbusds.jose.jwk.OctetKeyPair; 028import com.nimbusds.jose.util.Base64URL; 029import net.jcip.annotations.ThreadSafe; 030 031 032/** 033 * Ed25519 verifier of {@link com.nimbusds.jose.JWSObject JWS objects}. 034 * Expects a public {@link OctetKeyPair} with {@code "crv"} Ed25519. 035 * Uses the Edwards-curve Digital Signature Algorithm (EdDSA). 036 * 037 * <p>See <a href="https://tools.ietf.org/html/rfc8037">RFC 8037</a> 038 * for more information. 039 * 040 * <p>This class is thread-safe. 041 * 042 * <p>Supports the following algorithm: 043 * 044 * <ul> 045 * <li>{@link com.nimbusds.jose.JWSAlgorithm#EdDSA} 046 * </ul> 047 * 048 * <p>with the following curve: 049 * 050 * <ul> 051 * <li>{@link com.nimbusds.jose.jwk.Curve#Ed25519} 052 * </ul> 053 * 054 * @author Tim McLean 055 * @version 2018-07-11 056 */ 057@ThreadSafe 058public class Ed25519Verifier extends EdDSAProvider implements JWSVerifier, CriticalHeaderParamsAware { 059 060 061 private final CriticalHeaderParamsDeferral critPolicy = new CriticalHeaderParamsDeferral(); 062 063 064 private final OctetKeyPair publicKey; 065 066 067 private final Ed25519Verify tinkVerifier; 068 069 070 /** 071 * Creates a new Ed25519 verifier. 072 * 073 * @param publicKey The public Ed25519 key. Must not be {@code null}. 074 * 075 * @throws JOSEException If the key subtype is not supported 076 */ 077 public Ed25519Verifier(final OctetKeyPair publicKey) 078 throws JOSEException { 079 080 this(publicKey, null); 081 } 082 083 084 /** 085 * Creates a Ed25519 verifier. 086 * 087 * @param publicKey The public Ed25519 key. Must not be {@code null}. 088 * @param defCritHeaders The names of the critical header parameters 089 * that are deferred to the application for 090 * processing, empty set or {@code null} if none. 091 * 092 * @throws JOSEException If the key subtype is not supported. 093 */ 094 public Ed25519Verifier(final OctetKeyPair publicKey, final Set<String> defCritHeaders) 095 throws JOSEException { 096 097 super(); 098 099 if (! Curve.Ed25519.equals(publicKey.getCurve())) { 100 throw new JOSEException("Ed25519Verifier only supports OctetKeyPairs with crv=Ed25519"); 101 } 102 103 if (publicKey.isPrivate()) { 104 throw new JOSEException("Ed25519Verifier requires a public key, use OctetKeyPair.toPublicJWK()"); 105 } 106 107 this.publicKey = publicKey; 108 tinkVerifier = new Ed25519Verify(publicKey.getDecodedX()); 109 critPolicy.setDeferredCriticalHeaderParams(defCritHeaders); 110 } 111 112 113 /** 114 * Returns the public key. 115 * 116 * @return An OctetKeyPair without the private part 117 */ 118 public OctetKeyPair getPublicKey() { 119 120 return publicKey; 121 } 122 123 124 @Override 125 public Set<String> getProcessedCriticalHeaderParams() { 126 127 return critPolicy.getProcessedCriticalHeaderParams(); 128 } 129 130 131 @Override 132 public Set<String> getDeferredCriticalHeaderParams() { 133 134 return critPolicy.getProcessedCriticalHeaderParams(); 135 } 136 137 138 @Override 139 public boolean verify(final JWSHeader header, 140 final byte[] signedContent, 141 final Base64URL signature) 142 throws JOSEException { 143 144 // Check alg field in header 145 final JWSAlgorithm alg = header.getAlgorithm(); 146 if (! JWSAlgorithm.EdDSA.equals(alg)) { 147 throw new JOSEException("Ed25519Verifier requires alg=EdDSA in JWSHeader"); 148 } 149 150 // Check for unrecognized "crit" properties 151 if (! critPolicy.headerPasses(header)) { 152 return false; 153 } 154 155 final byte[] jwsSignature = signature.decode(); 156 157 try { 158 tinkVerifier.verify(jwsSignature, signedContent); 159 return true; 160 161 } catch (GeneralSecurityException e) { 162 return false; 163 } 164 } 165}