diff options
Diffstat (limited to 'core/src/main/java/net/oauth/signature/RSA_SHA1.java')
-rwxr-xr-x | core/src/main/java/net/oauth/signature/RSA_SHA1.java | 239 |
1 files changed, 239 insertions, 0 deletions
diff --git a/core/src/main/java/net/oauth/signature/RSA_SHA1.java b/core/src/main/java/net/oauth/signature/RSA_SHA1.java new file mode 100755 index 0000000..0aa99f1 --- /dev/null +++ b/core/src/main/java/net/oauth/signature/RSA_SHA1.java @@ -0,0 +1,239 @@ +/* + * Copyright 2007 Google, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.oauth.signature; + +import java.io.ByteArrayInputStream; +import java.io.UnsupportedEncodingException; +import java.security.GeneralSecurityException; +import java.security.KeyFactory; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.Signature; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.security.spec.EncodedKeySpec; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; + +import net.oauth.OAuth; +import net.oauth.OAuthAccessor; +import net.oauth.OAuthException; + +/** + * Class to handle RSA-SHA1 signatures on OAuth requests. A consumer + * that wishes to use public-key signatures on messages does not need + * a shared secret with the service provider, but it needs a private + * RSA signing key. You create it like this: + * + * OAuthConsumer c = new OAuthConsumer(callback_url, consumer_key, + * null, provider); + * c.setProperty(RSA_SHA1.PRIVATE_KEY, consumer_privateRSAKey); + * + * consumer_privateRSAKey must be an RSA signing key and + * of type java.security.PrivateKey, String, or byte[]. In the latter two + * cases, the key must be PKCS#8-encoded (byte[]) or PKCS#8-encoded and + * then Base64-encoded (String). + * + * A service provider that wishes to verify signatures made by such a + * consumer does not need a shared secret with the consumer, but it needs + * to know the consumer's public key. You create the necessary + * OAuthConsumer object (on the service provider's side) like this: + * + * OAuthConsumer c = new OAuthConsumer(callback_url, consumer_key, + * null, provider); + * c.setProperty(RSA_SHA1.PUBLIC_KEY, consumer_publicRSAKey); + * + * consumer_publicRSAKey must be the consumer's public RSAkey and + * of type java.security.PublicKey, String, or byte[]. In the latter two + * cases, the key must be X509-encoded (byte[]) or X509-encoded and + * then Base64-encoded (String). + * + * Alternatively, a service provider that wishes to verify signatures made + * by such a consumer can use a X509 certificate containing the consumer's + * public key. You create the necessary OAuthConsumer object (on the service + * provider's side) like this: + * + * OAuthConsumer c = new OAuthConsumer(callback_url, consumer_key, + * null, provider); + * c.setProperty(RSA_SHA1.X509_CERTIFICATE, consumer_cert); + * + * consumer_cert must be a X509 Certificate containing the consumer's public + * key and be of type java.security.cert.X509Certificate, String, + * or byte[]. In the latter two cases, the certificate must be DER-encoded + * (byte[]) or PEM-encoded (String). + * + * @author Dirk Balfanz + * @hide + * + */ +public class RSA_SHA1 extends OAuthSignatureMethod { + + final static public String PRIVATE_KEY = "RSA-SHA1.PrivateKey"; + final static public String PUBLIC_KEY = "RSA-SHA1.PublicKey"; + final static public String X509_CERTIFICATE = "RSA-SHA1.X509Certificate"; + + private PrivateKey privateKey = null; + private PublicKey publicKey = null; + + @Override + protected void initialize(String name, OAuthAccessor accessor) + throws OAuthException { + super.initialize(name, accessor); + + Object privateKeyObject = accessor.consumer.getProperty(PRIVATE_KEY); + try { + if (privateKeyObject != null) { + if (privateKeyObject instanceof PrivateKey) { + privateKey = (PrivateKey)privateKeyObject; + } else if (privateKeyObject instanceof String) { + privateKey = getPrivateKeyFromPem((String)privateKeyObject); + } else if (privateKeyObject instanceof byte[]) { + privateKey = getPrivateKeyFromDer((byte[])privateKeyObject); + } else { + throw new IllegalArgumentException( + "Private key set through RSA_SHA1.PRIVATE_KEY must be of " + + "type PrivateKey, String, or byte[], and not " + + privateKeyObject.getClass().getName()); + } + } + + Object publicKeyObject = accessor.consumer.getProperty(PUBLIC_KEY); + if (publicKeyObject != null) { + if (publicKeyObject instanceof PublicKey) { + publicKey = (PublicKey)publicKeyObject; + } else if (publicKeyObject instanceof String) { + publicKey = getPublicKeyFromPem((String)publicKeyObject); + } else if (publicKeyObject instanceof byte[]) { + publicKey = getPublicKeyFromDer((byte[])publicKeyObject); + } else { + throw new IllegalArgumentException( + "Public key set through RSA_SHA1.PRIVATE_KEY must be of " + + "type PublicKey, String, or byte[], and not " + + publicKeyObject.getClass().getName()); + } + } else { // public key was null. perhaps they gave us a X509 cert. + Object certObject = accessor.consumer.getProperty(X509_CERTIFICATE); + if (certObject != null) { + if (certObject instanceof X509Certificate) { + publicKey = ((X509Certificate) certObject).getPublicKey(); + } else if (certObject instanceof String) { + publicKey = getPublicKeyFromPemCert((String)certObject); + } else if (certObject instanceof byte[]) { + publicKey = getPublicKeyFromDerCert((byte[])certObject); + } else { + throw new IllegalArgumentException( + "X509Certificate set through RSA_SHA1.X509_CERTIFICATE" + + " must be of type X509Certificate, String, or byte[]," + + " and not " + certObject.getClass().getName()); + } + } + } + } catch (GeneralSecurityException e) { + throw new OAuthException(e); + } + } + + private PublicKey getPublicKeyFromPemCert(String certObject) + throws GeneralSecurityException { + CertificateFactory fac = CertificateFactory.getInstance("X509"); + ByteArrayInputStream in = new ByteArrayInputStream(certObject.getBytes()); + X509Certificate cert = (X509Certificate)fac.generateCertificate(in); + return cert.getPublicKey(); + } + + private PublicKey getPublicKeyFromDerCert(byte[] certObject) + throws GeneralSecurityException { + CertificateFactory fac = CertificateFactory.getInstance("X509"); + ByteArrayInputStream in = new ByteArrayInputStream(certObject); + X509Certificate cert = (X509Certificate)fac.generateCertificate(in); + return cert.getPublicKey(); + } + + private PublicKey getPublicKeyFromDer(byte[] publicKeyObject) + throws GeneralSecurityException { + KeyFactory fac = KeyFactory.getInstance("RSA"); + EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(publicKeyObject); + return fac.generatePublic(pubKeySpec); + } + + private PublicKey getPublicKeyFromPem(String publicKeyObject) + throws GeneralSecurityException { + return getPublicKeyFromDer(decodeBase64(publicKeyObject)); + } + + private PrivateKey getPrivateKeyFromDer(byte[] privateKeyObject) + throws GeneralSecurityException { + KeyFactory fac = KeyFactory.getInstance("RSA"); + EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(privateKeyObject); + return fac.generatePrivate(privKeySpec); + } + + private PrivateKey getPrivateKeyFromPem(String privateKeyObject) + throws GeneralSecurityException { + return getPrivateKeyFromDer(decodeBase64(privateKeyObject)); + } + + @Override + protected String getSignature(String baseString) throws OAuthException { + try { + byte[] signature = sign(baseString.getBytes(OAuth.ENCODING)); + return base64Encode(signature); + } catch (UnsupportedEncodingException e) { + throw new OAuthException(e); + } catch (GeneralSecurityException e) { + throw new OAuthException(e); + } + } + + @Override + protected boolean isValid(String signature, String baseString) + throws OAuthException { + try { + return verify(decodeBase64(signature), + baseString.getBytes(OAuth.ENCODING)); + } catch (UnsupportedEncodingException e) { + throw new OAuthException(e); + } catch (GeneralSecurityException e) { + throw new OAuthException(e); + } + } + + private byte[] sign(byte[] message) throws GeneralSecurityException { + if (privateKey == null) { + throw new IllegalStateException("need to set private key with " + + "OAuthConsumer.setProperty when " + + "generating RSA-SHA1 signatures."); + } + Signature signer = Signature.getInstance("SHA1withRSA"); + signer.initSign(privateKey); + signer.update(message); + return signer.sign(); + } + + private boolean verify(byte[] signature, byte[] message) + throws GeneralSecurityException { + if (publicKey == null) { + throw new IllegalStateException("need to set public key with " + + " OAuthConsumer.setProperty when " + + "verifying RSA-SHA1 signatures."); + } + Signature verifier = Signature.getInstance("SHA1withRSA"); + verifier.initVerify(publicKey); + verifier.update(message); + return verifier.verify(signature); + } +} |