bdrister / AquaticPrime

Mac software licensing code using cryptographically signed license files
http://github.com/bdrister/AquaticPrime
307 stars 91 forks source link

Lion SDK deprecations #22

Open fraserhess opened 12 years ago

fraserhess commented 12 years ago

Building the CoreFoundation AquaticPrime against the 10.7 SDK finds deprecated methods:

/Users/fraser/Development/Harmony/AquaticPrime.c:41:14: warning: 'RSA_new' is deprecated [-Wdeprecated-declarations] rsaKey = RSA_new(); /Users/fraser/Development/Harmony/AquaticPrime.c:44:5: warning: 'BN_hex2bn' is deprecated [-Wdeprecated-declarations] BN_hex2bn(&rsaKey->e, "3"); /Users/fraser/Development/Harmony/AquaticPrime.c:63:9: warning: 'BN_hex2bn' is deprecated [-Wdeprecated-declarations] BN_hex2bn(&rsaKey->n, keyCStringBuffer); /Users/fraser/Development/Harmony/AquaticPrime.c:67:9: warning: 'BN_dec2bn' is deprecated [-Wdeprecated-declarations] BN_dec2bn(&rsaKey->n, keyCStringBuffer); /Users/fraser/Development/Harmony/AquaticPrime.c:132:27: warning: 'RSA_size' is deprecated [-Wdeprecated-declarations] int checkDigestMaxSize = RSA_size(rsaKey)-11; /Users/fraser/Development/Harmony/AquaticPrime.c:136:3: warning: 'RSA_public_decrypt' is deprecated [-Wdeprecated-declarations] RSA_public_decrypt((int)sigDataLength, sigBytes, checkDigest, rsaKey, RSA_PKCS1_PADDING) != SHA_DIGEST_LENGTH) { /Users/fraser/Development/Harmony/AquaticPrime.c:168:5: warning: 'SHA1_Init' is deprecated [-Wdeprecated-declarations] SHA1_Init(&ctx); /Users/fraser/Development/Harmony/AquaticPrime.c:181:9: warning: 'SHA1_Update' is deprecated [-Wdeprecated-declarations] SHA1_Update(&ctx, valueBytes, strlen(valueBytes)); /Users/fraser/Development/Harmony/AquaticPrime.c:185:5: warning: 'SHA1_Final' is deprecated [-Wdeprecated-declarations] SHA1_Final(digest, &ctx);

9 warnings generated.

The SHA1 functions can be replaced with CC_SHA1 equivalents. Not sure about the RSA or BN functions.

lksoft commented 12 years ago

Has anyone figured out what to use as replacements for the RSA* methods here?

fraserhess commented 12 years ago

Per Apple at WWDC 2011, if you need to use OpenSSL, statically link it. This is what I'm doing.

lksoft commented 12 years ago

This doesn't really solve the problem with the warnings though during compilation, does it? Are you just suppressing those?

fraserhess commented 12 years ago

No, it doesn't just suppress those. Look at slide 55 of session 212 from WWDC 2011. It says that if you need to stick with OpenSSL, get it from macports (port install openssl) and statically link it. This means you are including the macports version of the OpenSSL library in your executable. In other words, your app will no longer use Apple's OpenSSL.

To statically link it: In your target, add /opt/local/include/ to your USER_HEADER_SEARCH_PATHS and /opt/local/lib/libcrypto.a /opt/local/lib/libz.a to your OTHER_LDFLAGS. Make sure ALWAYS_SEARCH_USER_PATHS = YES

fraserhess commented 12 years ago

Oh and remove -lcrypto in OTHER_LDFLAGS

lksoft commented 12 years ago

Ah, okay cool. I will look at the session and use those settings. That makes sense.

ghost commented 12 years ago

I didn't like the warnings either, and I didn't like increasing the code-size by statically linking so I have a replacement class that uses the new Security Transforms API that I will post somewhere if you're interested.

tuscland commented 12 years ago

@mwaters , I'm interested!

ghost commented 12 years ago

@tuscland I've got it on my github account if you'd like to take a look. I'd class it as work in progress at the moment, although for my own purposes I am using this in the next app update, and it validates signatures fine in Lion and Mountain Lion, which is great.

The big difference between the existing code and the new is that the existing code just needs the raw 1024 bit key(s) to sign and verify. But the new Apple security framework imports keys encoded as PEM format keys (public and private). On the public side, it's very easy to generate a PEM encoded version of the raw key so verifying signatures is working fine. But on the private key side, there's more information in the PEM file than we have in the raw private key and I don't know if there's a way to re-generate the missing data from what we have. The file encodes the public and private keys, but also the two large primes.

So the new library doesn't import the private key as a hex string so you can't use the class to sign licenses if you already have the raw 1024 bit public and private keys. Interestingly, I did manage to edit the raw content of the private key (decoded the base64 and edited with 0xED) and substituted my old private key, changed the RSA modulus to 3 and re-encoded it as PEM. This then works find in openssl at the command line when signing. So it looks like the Apple security framework is just applying more validation than openssl does when signing. However, for me it's fine.

If you don't have the keys already and want to generate new ones, this will produce a PEM encoded public and private key that you can use and it's possible to just extract the raw keys if you need to from the PEM data. This could be used to pass to the existing code, or to payment providers such as Fastspring who use the Aquatic Prime library to generate license files.

Hope that helps in some way. I'm sure if everyone works together we can update the whole thing!

tuscland commented 12 years ago

@mwaters: Thank you very much for the very interesting information!

At the moment, I am contemplating what are the possible solutions. As I am currently supporting 10.6 and higher, deprecation is not an issue, but will surely will become real when I migrate my code to support 10.7 and higher SDKs.

I will have a look and if I have suggestions, I will make sure to share them.

On 22 sept. 2012, at 11:50, mwaters notifications@github.com wrote:

@tuscland I've got it on my github account if you'd like to take a look. I'd class it as work in progress at the moment, although for my own purposes I am using this in the next app update, and it validates signatures fine in Lion and Mountain Lion, which is great.

The big difference between the existing code and the new is that the existing code just needs the raw 1024 bit key(s) to sign and verify. But the new Apple security framework imports keys encoded as PEM format keys (public and private). On the public side, it's very easy to generate a PEM encoded version of the raw key so verifying signatures is working fine. But on the private key side, there's more information in the PEM file than we have in the raw private key and I don't know if there's a way to re-generate the missing data from what we have. The file encodes the public and private keys, but also the two large primes.

So the new library doesn't import the private key as a hex string so you can't use the class to sign licenses if you already have the raw 1024 bit public and private keys. Interestingly, I did manage to edit the raw content of the private key (decoded the base64 and edited with 0xED) and substituted my old private key, changed the RSA modulus to 3 and re-encoded it as PEM. This then works find in openssl at the command line when signing. So it looks like the Apple security framework is just applying more validation than openssl does when signing. However, for me it's fine.

If you don't have the keys already and want to generate new ones, this will produce a PEM encoded public and private key that you can use and it's possible to just extract the raw keys if you need to from the PEM data. This could be used to pass to the existing code, or to payment providers such as Fastspring who use the Aquatic Prime library to generate license files.

Hope that helps in some way. I'm sure if everyone works together we can update the whole thing!

— Reply to this email directly or view it on GitHub.

adib commented 11 years ago

I suppose the new library imports raw hex keys now via the pemKeyFromRawHex: method?

ghost commented 11 years ago

Yes, that's right. If you already have a keypair in raw hex format, you can use the class as before, simply passing your raw public key. Here's my code:

// Read the license file
NSString *key = [self myAquaticPrimeKey];
AquaticPrime *licenseValidator = [AquaticPrime aquaticPrimeWithKey:key];

The class cannot sign license files using only the raw keys as I haven't found a way to reconstruct all the other components that it needs in the PEM encoded private key. However, if you have a PEM encoded key pair the class is able to sign and verify. If you have legacy code and only have a raw (1024 bit) key pair, the class can verify properly but you'll most likely have a PHP class on your server somewhere generating the signatures. We use Fastspring as our payment provider, and they generate signatures as part of the sale. Another option which I can also fallback on is a modified version of the PHP example code which instead uses openssl directly to sign the plist hash.

$cmd = "openssl rsautl -sign -in \"$hash_filename\" -inkey \"$privKeyFile\" -out \"$sign_filename\""; $retVal = 0; $output = array(); exec($cmd, $output, $retVal);

All the best, Mathew

adib commented 11 years ago

Thanks!