001package com.nimbusds.jose.crypto; 002 003 004import java.security.InvalidKeyException; 005import java.security.Signature; 006import java.security.SignatureException; 007import java.security.interfaces.ECPublicKey; 008import java.util.Set; 009 010import net.jcip.annotations.ThreadSafe; 011 012import com.nimbusds.jose.*; 013import com.nimbusds.jose.jwk.ECKey; 014import com.nimbusds.jose.util.Base64URL; 015 016 017/** 018 * Elliptic Curve Digital Signature Algorithm (ECDSA) verifier of 019 * {@link com.nimbusds.jose.JWSObject JWS objects}. This class is thread-safe. 020 * 021 * <p>Supports the following algorithms: 022 * 023 * <ul> 024 * <li>{@link com.nimbusds.jose.JWSAlgorithm#ES256} 025 * <li>{@link com.nimbusds.jose.JWSAlgorithm#ES384} 026 * <li>{@link com.nimbusds.jose.JWSAlgorithm#ES512} 027 * </ul> 028 * 029 * @author Axel Nennker 030 * @author Vladimir Dzhuvinov 031 * @version 2015-06-07 032 */ 033@ThreadSafe 034public class ECDSAVerifier extends ECDSAProvider implements JWSVerifier, CriticalHeaderParamsAware { 035 036 037 /** 038 * The critical header policy. 039 */ 040 private final CriticalHeaderParamsDeferral critPolicy = new CriticalHeaderParamsDeferral(); 041 042 043 /** 044 * The public EC key. 045 */ 046 private final ECPublicKey publicKey; 047 048 049 /** 050 * Creates a new Elliptic Curve Digital Signature Algorithm (ECDSA) 051 * verifier. 052 * 053 * @param publicKey The public EC key. Must not be {@code null}. 054 * 055 * @throws JOSEException If the elliptic curve of key is not supported. 056 */ 057 public ECDSAVerifier(final ECPublicKey publicKey) 058 throws JOSEException { 059 060 this(publicKey, null); 061 } 062 063 064 065 /** 066 * Creates a new Elliptic Curve Digital Signature Algorithm (ECDSA) 067 * verifier. 068 * 069 * @param ecJWK The EC JSON Web Key (JWK). Must not be {@code null}. 070 * 071 * @throws JOSEException If the elliptic curve of key is not supported. 072 */ 073 public ECDSAVerifier(final ECKey ecJWK) 074 throws JOSEException { 075 076 this(ecJWK.toECPublicKey()); 077 } 078 079 080 /** 081 * Creates a new Elliptic Curve Digital Signature Algorithm (ECDSA) 082 * verifier. 083 * 084 * @param publicKey The public EC key. Must not be {@code null}. 085 * @param defCritHeaders The names of the critical header parameters 086 * that are deferred to the application for 087 * processing, empty set or {@code null} if none. 088 * 089 * @throws JOSEException If the elliptic curve of key is not supported. 090 */ 091 public ECDSAVerifier(final ECPublicKey publicKey, final Set<String> defCritHeaders) 092 throws JOSEException { 093 094 super(ECDSA.resolveAlgorithm(publicKey)); 095 096 this.publicKey = publicKey; 097 098 critPolicy.setDeferredCriticalHeaderParams(defCritHeaders); 099 } 100 101 102 /** 103 * Returns the public EC key. 104 * 105 * @return The public EC key. 106 */ 107 public ECPublicKey getPublicKey() { 108 109 return publicKey; 110 } 111 112 113 @Override 114 public Set<String> getProcessedCriticalHeaderParams() { 115 116 return critPolicy.getProcessedCriticalHeaderParams(); 117 } 118 119 120 @Override 121 public Set<String> getDeferredCriticalHeaderParams() { 122 123 return critPolicy.getProcessedCriticalHeaderParams(); 124 } 125 126 127 @Override 128 public boolean verify(final JWSHeader header, 129 final byte[] signedContent, 130 final Base64URL signature) 131 throws JOSEException { 132 133 final JWSAlgorithm alg = header.getAlgorithm(); 134 135 if (! supportedJWSAlgorithms().contains(alg)) { 136 throw new JOSEException(AlgorithmSupportMessage.unsupportedJWSAlgorithm(alg, supportedJWSAlgorithms())); 137 } 138 139 if (! critPolicy.headerPasses(header)) { 140 return false; 141 } 142 143 final byte[] jwsSignature = signature.decode(); 144 145 final byte[] derSignature; 146 147 try { 148 derSignature = ECDSA.transcodeSignatureToDER(jwsSignature); 149 } catch (JOSEException e) { 150 // Invalid signature format 151 return false; 152 } 153 154 Signature sig = ECDSA.getSignerAndVerifier(alg, getJCAContext().getProvider()); 155 156 try { 157 sig.initVerify(publicKey); 158 sig.update(signedContent); 159 return sig.verify(derSignature); 160 161 } catch (InvalidKeyException e) { 162 throw new JOSEException("Invalid EC public key: " + e.getMessage(), e); 163 } catch (SignatureException e) { 164 return false; 165 } 166 } 167}