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