I'm following Apple's guide towards composing a CloudKit Web Services request. The bit I'm having trouble with is Step 2, under "Authenticate Web Service Requests":
- Compute the ECDSA signature of this message with your private key.
It appears that the documentation and the actual API for Ruby’s OpenSSL EC support are both currently rather lacking. In particular, in Ruby <= 2.3.1 the
OpenSSL::PKey::EC doesn’t follow the same API as RSA and DSA keys for signing and verifying. What you would want to do, but currently can’t with EC keys, is this (all the code here assumes you have called
require 'openssl' somewhere):
# Get the key, here I'm reading the file priv_key = OpenSSL::PKey.read(File.read('eckey.pem')) # This should be the appropriately formatted string data = "some data to sign" # The hash algorithm, I assume SHA256 is being used digest = OpenSSL::Digest::SHA256.new # This doesn't work in 2.3.1, but does in 2.4.0-preview1 signature = priv_key.sign(digest, data)
As I note in the comments, this does work in Ruby 2.4.0-preview1, but that’s likely not much use to you.
To get it working with current Ruby, you need to do something like this:
# As before: priv_key = OpenSSL::PKey.read(File.read('eckey.pem')) data = "some data to sign" signature = priv_key.dsa_sign_asn1(OpenSSL::Digest::SHA256.digest(data))
Both these techniques give you a binary string. I think you will need to base64 encode it before adding it as your request header.
To extract the public key to check the signature verifies is also a bit tricky (although you could just use the
openssl command line and read in the file). The
public_key methods returns an
OpenSSL::PKey::EC::Point object rather than an actual key, so we need to recreate one from the private key. The
verify method does work on Ruby 2.3.1:
pub = OpenSSL::PKey::EC.new(priv_key.group) pub.public_key = priv_key.public_key data = "some data to sign" digest = OpenSSL::Digest::SHA256.new puts pub.verify(digest, sig, data)
The Apple page doesn’t appear to specify the hash algorithm to use, but from what I’ve seen it looks like SHA-256 is right. (Also I could have got this completely wrong and Apple are using a completely different format. I’d be keen to know whether or not this code works you you).