SecKeychain: sign data with RSA PKCS1 PSS PADDING algorithm

418 views Asked by At

I'm trying to implement c++ external PKI sign method for openvpn client. I need to sign data with RSA_PKCS1_PSS_PADDING algorithm, but Security framework has no such method.

There is my function:

void MacStore::sign(const std::string &data, std::string &sig, const std::string &algorithm,
                    const std::string &hashalg, const std::string &saltlen) {
    SecKeyAlgorithm alg;
    if (!hashalg.empty()) {
        alg = kSecKeyAlgorithmRSASignatureDigestPSSSHA256;
    } else {
        alg = kSecKeyAlgorithmRSASignatureMessagePSSSHA1;
    }
    openvpn::BufferAllocated signdata(256, openvpn::BufferAllocated::GROW);
    openvpn::base64->decode(signdata, data);
    SecKeyRef pkey;
    OSStatus status = SecIdentityCopyPrivateKey((SecIdentityRef)identity, &pkey);
    if (status) {
        // error
        return;
    }
    auto isSupported = SecKeyIsAlgorithmSupported(pkey, kSecKeyOperationTypeSign, alg);
    std::cout << (isSupported ? "supported" : "not supported") << std::endl;
    auto dataToSign = CFStringCreateWithCString(nullptr, buf_c_str(signdata), kCFStringEncodingASCII);
    auto dataToSignPtr = CFStringCreateExternalRepresentation(nullptr, dataToSign, kCFStringEncodingASCII, 0);

    CFErrorRef err = nullptr;
    auto signature = SecKeyCreateSignature(pkey, alg, dataToSignPtr, &err);
    if (err) {
        return;
    }

    SecCertificateRef cert;
    SecIdentityCopyCertificate((SecIdentityRef)identity, &cert);
    SecKeyRef pub;
    SecCertificateCopyPublicKey(cert, &pub);

    int signatureLength = CFDataGetLength(signature);
    openvpn::BufferAllocated signer(signatureLength, openvpn::BufferAllocated::ARRAY);
    auto range = CFRangeMake(0, signatureLength);
    CFDataGetBytes(signature, range, signer.data());
    signer.set_size(signatureLength);

    CFRelease(signature);
    CFRelease(dataToSign);

    sig = openvpn::base64->encode(signer);
    std::cout << "SIGNATURE[" << signatureLength << "]: " << signer.c_str() << std::endl;
}

On connect server log prints:

// Verifies certificate - OK
OpenSSL: error:02000087:rsa routines::salt length recovery failed
Dec 09 12:51:38 server openvpn[29669]: 10.31.154.84:50843 OpenSSL: error:1C880004:Provider routines::RSA lib
Dec 09 12:51:38 server openvpn[29669]: 10.31.154.84:50843 OpenSSL: error:0A00007B:SSL routines::bad signature
Dec 09 12:51:38 server openvpn[29669]: 10.31.154.84:50843 TLS_ERROR: BIO read tls_read_plaintext error
Dec 09 12:51:38 server openvpn[29669]: 10.31.154.84:50843 TLS Error: TLS object -> incoming plaintext read error
Dec 09 12:51:38 server openvpn[29669]: 10.31.154.84:50843 TLS Error: TLS handshake failed
Dec 09 12:51:38 server openvpn[29669]: 10.31.154.84:50843 Fatal TLS error (check_tls_errors_co), restarting
Dec 09 12:51:38 server openvpn[29669]: 10.31.154.84:50843 SIGUSR1[soft,tls-error] received, client-instance restarting

My question is: which SecAlgorithm should I choose to produce valid rsa signature?

UPD: Verify method with same data to sign returns false(invalid signature) as well...

0

There are 0 answers