bool OpenSSLCryptoKeyRSA::verifySHA1PKCS1Base64Signature()

in xsec/enc/OpenSSL/OpenSSLCryptoKeyRSA.cpp [438:556]


bool OpenSSLCryptoKeyRSA::verifySHA1PKCS1Base64Signature(
        const unsigned char* hashBuf,
        unsigned int hashLen,
        const char * base64Signature,
        unsigned int sigLen,
        XSECCryptoHash::HashType type) const {

    // Use the currently loaded key to validate the Base64 encoded signature

    if (mp_rsaKey == NULL) {
        throw XSECCryptoException(XSECCryptoException::RSAError,
            "OpenSSL:RSA - Attempt to validate signature with empty key");
    }

    XSECCryptoKey::KeyType keyType = getKeyType();
    if (keyType != KEY_RSA_PAIR && keyType != KEY_RSA_PUBLIC) {
        throw XSECCryptoException(XSECCryptoException::RSAError,
            "OpenSSL:RSA - Attempt to validate signature without public key");
    }

    char* cleanedBase64Signature;
    unsigned int cleanedBase64SignatureLen = 0;

    cleanedBase64Signature =
        XSECCryptoBase64::cleanBuffer(base64Signature, sigLen, cleanedBase64SignatureLen);
    ArrayJanitor<char> j_cleanedBase64Signature(cleanedBase64Signature);

    int sigValLen;
    unsigned char* sigVal = new unsigned char[sigLen + 1];
    ArrayJanitor<unsigned char> j_sigVal(sigVal);

    EvpEncodeCtxRAII dctx;

    if (!dctx.of()) {
        throw XSECCryptoException(XSECCryptoException::RSAError,
            "OpenSSL:RSA - allocation fail during Context Creation");
    }

    EVP_DecodeInit(dctx.of());
    int rc = EVP_DecodeUpdate(dctx.of(),
                          sigVal,
                          &sigValLen,
                          (unsigned char *) cleanedBase64Signature,
                          cleanedBase64SignatureLen);

    if (rc < 0) {
        throw XSECCryptoException(XSECCryptoException::RSAError,
            "OpenSSL:RSA - Error during Base64 Decode");
    }
    int t = 0;

    EVP_DecodeFinal(dctx.of(), &sigVal[sigValLen], &t);

    sigValLen += t;

    // OpenSSL allows the signature size to be less than the key size.
    // Java does not and the spec requires that this fail, so we have to
    // perform this check.

    int keySize = RSA_size(mp_rsaKey);
    if (keySize != sigValLen) {
            throw XSECCryptoException(XSECCryptoException::RSAError,
                "OpenSSL:RSA - Signature size does not match key size");
    }

    // Now decrypt

    unsigned char* decryptBuf;

    // Decrypt will always be longer than (RSA_len(key) - 11)
    decryptBuf = new unsigned char[RSA_size(mp_rsaKey)];
    ArrayJanitor<unsigned char> j_decryptBuf(decryptBuf);

    // Note at this time only supports PKCS1 padding
    // As that is what is defined in the standard.
    // If this ever changes we will need to pass some paramaters
    // into this function to allow it to determine what the
    // padding should be and what the message digest OID should
    // be.

    int decryptSize = RSA_public_decrypt(sigValLen,
                                             sigVal,
                                             decryptBuf,
                                             mp_rsaKey,
                                             RSA_PKCS1_PADDING);

    if (decryptSize < 0) {
        // Really - this is a failed signature check, not an exception!
        return false;
    }

    /* Check the OID */
    int oidLen = 0;
    unsigned char * oid = getRSASigOID(type, oidLen);

    if (oid == NULL) {
        throw XSECCryptoException(XSECCryptoException::RSAError,
            "OpenSSL:RSA::verify() - Unsupported HASH algorithm for RSA");
    }

    if (decryptSize != (int) (oidLen + hashLen) || hashLen != oid[oidLen-1]) {
        return false;
    }

    for (t = 0; t < oidLen; ++t) {
        if (oid[t] != decryptBuf[t]) {
            return false;
        }
    }

    for (;t < decryptSize; ++t) {
        if (hashBuf[t-oidLen] != decryptBuf[t]) {
            return false;
        }
    }

    // All OK
    return true;
}