/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 com.google.j2objc.security; import java.io.IOException; import java.io.OutputStream; import java.security.InvalidKeyException; import java.security.InvalidParameterException; import java.security.Key; import java.security.PrivateKey; import java.security.PublicKey; import java.security.SignatureException; import java.security.SignatureSpi; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; /*-[ #include "NSDataOutputStream.h" #include <CommonCrypto/CommonDigest.h> #include <Security/Security.h> // Public iOS API (Security/SecKey.h). These functions are private in OS X due // to issues with ECC certificates, but are still useful for jre_emul unit tests. OSStatus SecKeyRawSign( SecKeyRef key, SecPadding padding, const uint8_t *dataToSign, size_t dataToSignLen, uint8_t *sig, size_t *sigLen); OSStatus SecKeyRawVerify( SecKeyRef key, SecPadding padding, const uint8_t *signedData, size_t signedDataLen, const uint8_t *sig, size_t sigLen); ]-*/ /** * Signature verification provider, implemented using the iOS Security Framework. * * @author Tom Ball */ public abstract class IosRSASignature extends SignatureSpi { protected OutputStream buffer = newNSDataOutputStream(); private Key key; @Override protected void engineInitVerify(PublicKey publicKey) throws InvalidKeyException { key = publicKey; } private static native OutputStream newNSDataOutputStream() /*-[ return [NSDataOutputStream stream]; ]-*/; @Override protected void engineInitSign(PrivateKey privateKey) throws InvalidKeyException { key = privateKey; } @Override protected void engineUpdate(byte b) throws SignatureException { try { buffer.write(b); } catch (IOException e) { throw new SignatureException(e); } } @Override protected void engineUpdate(byte[] b, int off, int len) throws SignatureException { try { buffer.write(b, off, len); } catch (IOException e) { throw new SignatureException(e); } } @Override protected byte[] engineSign() throws SignatureException { if (key == null || !(key instanceof RSAPrivateKey)) { throw new SignatureException("Needs RSA private key"); } if (!(key instanceof IosRSAKey.IosRSAPrivateKey)) { throw new SignatureException("unknown key type: " + key.getClass()); } long privateKey = ((IosRSAKey.IosRSAPrivateKey) key).getSecKeyRef(); return nativeEngineSign(privateKey); } protected abstract byte[] nativeEngineSign(long nativeKey); protected abstract boolean nativeEngineVerify(long nativeKey, byte[] sigBytes); @Override protected boolean engineVerify(byte[] sigBytes) throws SignatureException { if (key == null || !(key instanceof RSAPublicKey)) { throw new SignatureException("Needs RSA public key"); } if (!(key instanceof IosRSAKey.IosRSAPublicKey)) { throw new SignatureException("unknown key type: " + key.getClass()); } long publicKey = ((IosRSAKey.IosRSAPublicKey) key).getSecKeyRef(); return nativeEngineVerify(publicKey, sigBytes); } @Override protected Object engineGetParameter(String param) throws InvalidParameterException { return null; } @Override protected void engineSetParameter(String param, Object value) throws InvalidParameterException { } /*-[ - (IOSByteArray *)nativeEngineSign:(SecKeyRef)privateKey hashBytes:(uint8_t *)hashBytes size:(size_t)hashBytesSize { size_t signedHashBytesSize = SecKeyGetBlockSize(privateKey); uint8_t *signedHashBytes = calloc(signedHashBytesSize, sizeof(uint8_t)); SecKeyRawSign(privateKey, kSecPaddingNone, hashBytes, hashBytesSize, signedHashBytes, &signedHashBytesSize); IOSByteArray *result = [IOSByteArray arrayWithBytes:(jbyte *)signedHashBytes count:(NSUInteger)signedHashBytesSize]; if (signedHashBytes) { free(signedHashBytes); } return result; } - (jboolean)nativeEngineVerify:(SecKeyRef)publicKey signature:(IOSByteArray *)signature hashBytes:(uint8_t *)hashBytes size:(size_t)hashBytesSize { size_t signatureSize = SecKeyGetBlockSize(publicKey); if (signatureSize != (size_t)signature->size_) { return false; } OSStatus status = SecKeyRawVerify(publicKey, kSecPaddingNone, hashBytes, hashBytesSize, (uint8_t*)signature->buffer_, signatureSize); return status == errSecSuccess; } ]-*/ public static final class MD5RSA extends IosRSASignature { @Override protected native byte[] nativeEngineSign(long nativeKey) /*-[ NSData *plainData = [(NSDataOutputStream *)buffer_ data]; size_t hashBytesSize = CC_MD5_DIGEST_LENGTH; uint8_t* hashBytes = malloc(hashBytesSize); if (!CC_MD5([plainData bytes], (CC_LONG)[plainData length], hashBytes)) { return nil; } IOSByteArray *result = [self nativeEngineSign:(SecKeyRef)nativeKey hashBytes:hashBytes size:hashBytesSize]; free(hashBytes); return result; ]-*/; @Override protected native boolean nativeEngineVerify(long nativeKey, byte[] sigBytes) /*-[ NSData *plainData = [(NSDataOutputStream *)buffer_ data]; size_t hashBytesSize = CC_MD5_DIGEST_LENGTH; uint8_t* hashBytes = malloc(hashBytesSize); if (!CC_MD5([plainData bytes], (CC_LONG)[plainData length], hashBytes)) { return false; } BOOL result = [self nativeEngineVerify:(SecKeyRef)nativeKey signature:sigBytes hashBytes:hashBytes size:hashBytesSize]; free(hashBytes); return result; ]-*/; } public static final class SHA1RSA extends IosRSASignature { @Override protected native byte[] nativeEngineSign(long nativeKey) /*-[ NSData *plainData = [(NSDataOutputStream *)buffer_ data]; size_t hashBytesSize = CC_SHA1_DIGEST_LENGTH; uint8_t* hashBytes = malloc(hashBytesSize); if (!CC_SHA1([plainData bytes], (CC_LONG)[plainData length], hashBytes)) { return nil; } IOSByteArray *result = [self nativeEngineSign:(SecKeyRef)nativeKey hashBytes:hashBytes size:hashBytesSize]; free(hashBytes); return result; ]-*/; @Override protected native boolean nativeEngineVerify(long nativeKey, byte[] sigBytes) /*-[ NSData *plainData = [(NSDataOutputStream *)buffer_ data]; size_t hashBytesSize = CC_SHA1_DIGEST_LENGTH; uint8_t* hashBytes = malloc(hashBytesSize); if (!CC_SHA1([plainData bytes], (CC_LONG)[plainData length], hashBytes)) { return false; } BOOL result = [self nativeEngineVerify:(SecKeyRef)nativeKey signature:sigBytes hashBytes:hashBytes size:hashBytesSize]; free(hashBytes); return result; ]-*/; } public static final class SHA256RSA extends IosRSASignature { @Override protected native byte[] nativeEngineSign(long nativeKey) /*-[ NSData *plainData = [(NSDataOutputStream *)buffer_ data]; size_t hashBytesSize = CC_SHA256_DIGEST_LENGTH; uint8_t* hashBytes = malloc(hashBytesSize); if (!CC_SHA256([plainData bytes], (CC_LONG)[plainData length], hashBytes)) { return nil; } IOSByteArray *result = [self nativeEngineSign:(SecKeyRef)nativeKey hashBytes:hashBytes size:hashBytesSize]; free(hashBytes); return result; ]-*/; @Override protected native boolean nativeEngineVerify(long nativeKey, byte[] sigBytes) /*-[ NSData *plainData = [(NSDataOutputStream *)buffer_ data]; size_t hashBytesSize = CC_SHA256_DIGEST_LENGTH; uint8_t* hashBytes = malloc(hashBytesSize); if (!CC_SHA256([plainData bytes], (CC_LONG)[plainData length], hashBytes)) { return false; } BOOL result = [self nativeEngineVerify:(SecKeyRef)nativeKey signature:sigBytes hashBytes:hashBytes size:hashBytesSize]; free(hashBytes); return result; ]-*/; } public static final class SHA384RSA extends IosRSASignature { @Override protected native byte[] nativeEngineSign(long nativeKey) /*-[ NSData *plainData = [(NSDataOutputStream *)buffer_ data]; size_t hashBytesSize = CC_SHA384_DIGEST_LENGTH; uint8_t* hashBytes = malloc(hashBytesSize); if (!CC_SHA384([plainData bytes], (CC_LONG)[plainData length], hashBytes)) { return nil; } IOSByteArray *result = [self nativeEngineSign:(SecKeyRef)nativeKey hashBytes:hashBytes size:hashBytesSize]; free(hashBytes); return result; ]-*/; @Override protected native boolean nativeEngineVerify(long nativeKey, byte[] sigBytes) /*-[ NSData *plainData = [(NSDataOutputStream *)buffer_ data]; size_t hashBytesSize = CC_SHA384_DIGEST_LENGTH; uint8_t* hashBytes = malloc(hashBytesSize); if (!CC_SHA384([plainData bytes], (CC_LONG)[plainData length], hashBytes)) { return false; } BOOL result = [self nativeEngineVerify:(SecKeyRef)nativeKey signature:sigBytes hashBytes:hashBytes size:hashBytesSize]; free(hashBytes); return result; ]-*/; } public static final class SHA512RSA extends IosRSASignature { @Override protected native byte[] nativeEngineSign(long nativeKey) /*-[ NSData *plainData = [(NSDataOutputStream *)buffer_ data]; size_t hashBytesSize = CC_SHA512_DIGEST_LENGTH; uint8_t* hashBytes = malloc(hashBytesSize); if (!CC_SHA512([plainData bytes], (CC_LONG)[plainData length], hashBytes)) { return nil; } IOSByteArray *result = [self nativeEngineSign:(SecKeyRef)nativeKey hashBytes:hashBytes size:hashBytesSize]; free(hashBytes); return result; ]-*/; @Override protected native boolean nativeEngineVerify(long nativeKey, byte[] sigBytes) /*-[ NSData *plainData = [(NSDataOutputStream *)buffer_ data]; size_t hashBytesSize = CC_SHA512_DIGEST_LENGTH; uint8_t* hashBytes = malloc(hashBytesSize); if (!CC_SHA512([plainData bytes], (CC_LONG)[plainData length], hashBytes)) { return false; } jboolean result = [self nativeEngineVerify:(SecKeyRef)nativeKey signature:sigBytes hashBytes:hashBytes size:hashBytesSize]; free(hashBytes); return result; ]-*/; } }