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 com.google.crypto.tink.subtle.Ed25519Verify; 022import com.nimbusds.jose.*; 023import com.nimbusds.jose.crypto.impl.CriticalHeaderParamsDeferral; 024import com.nimbusds.jose.crypto.impl.EdDSAProvider; 025import com.nimbusds.jose.jwk.Curve; 026import com.nimbusds.jose.jwk.OctetKeyPair; 027import com.nimbusds.jose.util.Base64URL; 028import net.jcip.annotations.ThreadSafe; 029 030import java.security.GeneralSecurityException; 031import java.util.Set; 032 033 034/** 035 * Ed25519 verifier of {@link com.nimbusds.jose.JWSObject JWS objects}. 036 * Expects a public {@link OctetKeyPair} with {@code "crv"} Ed25519. 037 * Uses the Edwards-curve Digital Signature Algorithm (EdDSA). 038 * 039 * <p>See <a href="https://tools.ietf.org/html/rfc8037">RFC 8037</a> 040 * for more information. 041 * 042 * <p>This class is thread-safe. 043 * 044 * <p>Supports the following algorithm: 045 * 046 * <ul> 047 * <li>{@link com.nimbusds.jose.JWSAlgorithm#EdDSA} 048 * <li>{@link com.nimbusds.jose.JWSAlgorithm#EdDSA} with 049 * {@link com.nimbusds.jose.jwk.Curve#Ed25519} 050 * </ul> 051 * 052 * @author Tim McLean 053 * @version 2024-05-07 054 */ 055@ThreadSafe 056public class Ed25519Verifier extends EdDSAProvider implements JWSVerifier, CriticalHeaderParamsAware { 057 058 059 private final CriticalHeaderParamsDeferral critPolicy = new CriticalHeaderParamsDeferral(); 060 061 062 private final OctetKeyPair publicKey; 063 064 065 private final Ed25519Verify tinkVerifier; 066 067 068 /** 069 * Creates a new Ed25519 verifier. 070 * 071 * @param publicKey The public Ed25519 key. Must not be {@code null}. 072 * 073 * @throws JOSEException If the key subtype is not supported 074 */ 075 public Ed25519Verifier(final OctetKeyPair publicKey) 076 throws JOSEException { 077 078 this(publicKey, null); 079 } 080 081 082 /** 083 * Creates an Ed25519 verifier. 084 * 085 * @param publicKey The public Ed25519 key. Must not be 086 * {@code null}. 087 * @param defCritHeaders The names of the critical header parameters 088 * that are deferred to the application for 089 * processing, empty set or {@code null} if none. 090 * 091 * @throws JOSEException If the key subtype is not supported. 092 */ 093 public Ed25519Verifier(final OctetKeyPair publicKey, final Set<String> defCritHeaders) 094 throws JOSEException { 095 096 super(); 097 098 if (! Curve.Ed25519.equals(publicKey.getCurve())) { 099 throw new JOSEException("Ed25519Verifier only supports OctetKeyPairs with crv=Ed25519"); 100 } 101 102 if (publicKey.isPrivate()) { 103 throw new JOSEException("Ed25519Verifier requires a public key, use OctetKeyPair.toPublicJWK()"); 104 } 105 106 this.publicKey = publicKey; 107 tinkVerifier = new Ed25519Verify(publicKey.getDecodedX()); 108 critPolicy.setDeferredCriticalHeaderParams(defCritHeaders); 109 } 110 111 112 /** 113 * Returns the public key. 114 * 115 * @return An OctetKeyPair without the private part 116 */ 117 public OctetKeyPair getPublicKey() { 118 119 return publicKey; 120 } 121 122 123 @Override 124 public Set<String> getProcessedCriticalHeaderParams() { 125 126 return critPolicy.getProcessedCriticalHeaderParams(); 127 } 128 129 130 @Override 131 public Set<String> getDeferredCriticalHeaderParams() { 132 133 return critPolicy.getProcessedCriticalHeaderParams(); 134 } 135 136 137 @Override 138 public boolean verify(final JWSHeader header, 139 final byte[] signedContent, 140 final Base64URL signature) 141 throws JOSEException { 142 143 // Check alg field in header 144 final JWSAlgorithm alg = header.getAlgorithm(); 145 if (! JWSAlgorithm.Ed25519.equals(alg) && ! JWSAlgorithm.EdDSA.equals(alg)) { 146 throw new JOSEException("Ed25519Verifier requires alg=Ed25519 or alg=EdDSA in JWSHeader"); 147 } 148 149 // Check for unrecognized "crit" properties 150 if (! critPolicy.headerPasses(header)) { 151 return false; 152 } 153 154 final byte[] jwsSignature = signature.decode(); 155 156 try { 157 tinkVerifier.verify(jwsSignature, signedContent); 158 return true; 159 160 } catch (GeneralSecurityException e) { 161 return false; 162 } 163 } 164}