001    package com.nimbusds.jose.crypto;
002    
003    
004    import java.util.HashSet;
005    import java.util.Set;
006    
007    import java.security.Signature;
008    import java.security.InvalidKeyException;
009    import java.security.SignatureException;
010    
011    import java.security.interfaces.RSAPublicKey;
012    
013    import net.jcip.annotations.ThreadSafe;
014    
015    import com.nimbusds.jose.JOSEException;
016    import com.nimbusds.jose.JWSHeaderFilter;
017    import com.nimbusds.jose.JWSVerifier;
018    import com.nimbusds.jose.ReadOnlyJWSHeader;
019    
020    import com.nimbusds.jose.util.Base64URL;
021    
022    
023    
024    /**
025     * RSA Signature-Scheme-with-Appendix (RSASSA) verifier of 
026     * {@link com.nimbusds.jose.JWSObject JWS objects}. This class is thread-safe.
027     *
028     * <p>Supports the following JSON Web Algorithms (JWAs):
029     *
030     * <ul>
031     *     <li>{@link com.nimbusds.jose.JWSAlgorithm#RS256}
032     *     <li>{@link com.nimbusds.jose.JWSAlgorithm#RS384}
033     *     <li>{@link com.nimbusds.jose.JWSAlgorithm#RS512}
034     * </ul>
035     *
036     * <p>Accepts the following JWS header parameters:
037     *
038     * <ul>
039     *     <li>{@code alg}
040     *     <li>{@code typ}
041     *     <li>{@code cty}
042     * </ul>
043     * 
044     * @author Vladimir Dzhuvinov
045     * @version $version$ (2012-10-23)
046     */
047    @ThreadSafe
048    public class RSASSAVerifier extends RSASSAProvider implements JWSVerifier {
049    
050    
051            /**
052             * The accepted JWS header parameters.
053             */
054            private static final Set<String> ACCEPTED_HEADER_PARAMETERS;
055            
056            
057            /**
058             * Initialises the accepted JWS header parameters.
059             */
060            static {
061            
062                    Set<String> params = new HashSet<String>();
063                    params.add("alg");
064                    params.add("typ");
065                    params.add("cty");
066                    
067                    ACCEPTED_HEADER_PARAMETERS = params;
068            }
069            
070            
071            /**
072             * The JWS header filter.
073             */
074            private DefaultJWSHeaderFilter headerFilter;
075            
076            
077            /**
078             * The public RSA key.
079             */
080            private final RSAPublicKey publicKey;
081            
082            
083            /**
084             * Creates a new RSA Signature-Scheme-with-Appendix (RSASSA) verifier.
085             *
086             * @param publicKey The public RSA key. Must not be {@code null}.
087             */
088            public RSASSAVerifier(final RSAPublicKey publicKey) {
089    
090                    if (publicKey == null)
091                            throw new IllegalArgumentException("The public RSA key must not be null");
092                    
093                    this.publicKey = publicKey;
094                    
095                    headerFilter = new DefaultJWSHeaderFilter(supportedAlgorithms(), ACCEPTED_HEADER_PARAMETERS);
096            }
097            
098            
099            /**
100             * Gets the public RSA key.
101             *
102             * @return The public RSA key.
103             */
104            public RSAPublicKey getPublicKey() {
105            
106                    return publicKey;
107            }
108            
109            
110            @Override
111            public JWSHeaderFilter getJWSHeaderFilter() {
112            
113                    return headerFilter;
114            }
115    
116    
117            @Override
118            public boolean verify(final ReadOnlyJWSHeader header, 
119                                  final byte[] signedContent, 
120                                  final Base64URL signature)
121                    throws JOSEException {
122                    
123                    Signature verifier = getRSASignerAndVerifier(header.getAlgorithm());
124                    
125                    try {
126                            verifier.initVerify(publicKey);
127                            verifier.update(signedContent);
128                            return verifier.verify(signature.decode());
129                            
130                    } catch (InvalidKeyException e) {
131                    
132                            throw new JOSEException("Invalid public RSA key: " + e.getMessage(), e);
133                    
134                    } catch (SignatureException e) {
135                    
136                            throw new JOSEException("RSA signature exception: " + e.getMessage(), e);
137                    }
138            }
139    }