10 Replies
      Latest reply on Apr 16, 2018 12:54 AM by eskimo
      pch-ivanti Level 1 Level 1 (0 points)

        App creates an RSA key pair suitable for sign/verify & encrypt/decrypt and stores them in a private keychain.  A CSR is generated via openssl, supplying the private key from above.  The CSR is sent to a server for registration.  The server returns a certificate, which is added to the keychain.  Keychain associates the cert & private key as an identity.  The app is built for 10.12+ and uses:  SecKeyCreateSignature, SecKeyVerifySignature, SecKeyCreateEncryptedData, SecKeyCreateDecryptedData

         

        Generating the key pair and returning the private key

        SecKeyGeneratePair, private key is returned in PEM fomat

               CFDataRef dataRef;

               SecKeyCopyExternalRepresentation( privateKey, &error );

               SecItemImportExportKeyParameters params = {};

               SecItemExport( privateKey, kSecFormatOpenSSL, kSecItemPemArmour, &params, &dataRef );

               NSString* pemString = [NSString stringWithUTF8String:[(__bridge NSData*)dataRef bytes]];

        for use with openssl req -new -key <private key> -config <config file>

         

        (In test code) I see different behaviors depending on which combination of keys is used.

        Here are three scenarios...

        1.  'original' key pair

          public key = query keychain for kSecAttrKeyClassPrivate by kSecAttrLabel

          private key = query keychain for kSecAttrKeyClassPublic by kSecAttrLabel

         

          testSignAndVerify SUCCEEDED

          testEncryptAndDecrypt SUCCEEDED

         

          But of course, this scenario cannot be used since the server will need to use the public key associated with the certificate to encrypt data and verify signatures.

         

         

        2.  identity provides both keys

          Fetch the identity by kSecAttrLabel

             public key = SecIdentityCopyCertificate;  SecCertificateCopyPublicKey

             private key = SecIdentityCopyPrivateKey

         

          testSignAndVerify FAILED - CSSMERR_CSP_OPERATION_AUTH_DENIED

          testEncryptAndDecrypt FAILED - CSSMERR_CSP_OPERATION_AUTH_DENIED

         

         

        3.  hybrid

          Fetch the identity by kSecAttrLabel

             public key = SecIdentityCopyCertificate;  SecCertificateCopyPublicKey

             private key = query keychain for kSecAttrKeyClassPublic by kSecAttrLabel

         

          testSignAndVerify FAILED - CSSMERR_CSP_VERIFY_FAILED

          testEncryptAndDecrypt FAILED - CSSMERR_CSP_INVALID_DATA

         

        So, I don't know what is going on, but it seems that whenever the certificate is involved, things don't work.  Looks like there is some sort of mismatch between the keys, but I checked the modulus and exponent - they match.

        • Re: Certificate-private key combo failure
          eskimo Apple Staff Apple Staff (12,015 points)

          App creates an RSA key pair suitable for sign/verify & encrypt/decrypt and stores them in a private keychain.  A CSR is generated via openssl, supplying the private key from above.

          Huh?  CSRs are meant to include the public key.

          Share and Enjoy

          Quinn “The Eskimo!”
          Apple Developer Relations, Developer Technical Support, Core OS/Hardware
          let myEmail = "eskimo" + "1" + "@apple.com"

            • Re: Certificate-private key combo failure
              foover Level 1 Level 1 (0 points)

              eskimo said, "Huh?  CSRs are meant to include the public key."

               

              Then I'm confused...

              Creating CSR using openssl:  /usr/bin/openssl req -new -key "/path/to/private/key" -config "path/to/config/file"

               

              openssl says:

              -key filename

                         This specifies the file to read the private key from. It also

                         accepts PKCS#8 format private keys for PEM format files.

                • Re: Certificate-private key combo failure
                  eskimo Apple Staff Apple Staff (12,015 points)

                  I’m not sure what’s going on with openssl (it’s possible that it’s deriving the public key from the private key, which is a relatively simple operation, at least for RSA) but CSRs definitely contain the public key.  Here’s a quote from the found of all knowledge:

                  In public key infrastructure (PKI) systems, a certificate signing request (also CSR or certification request) is a message sent from an applicant to a certificate authority in order to apply for a digital identity certificate. It usually contains the public key for which the certificate should be issued, identifying information (such as a domain name) and integrity protection (e.g., a digital signature).

                  If you think about it this is the only option that makes sense.  Here’s a typical CSR sequence:

                  1. You generate a key pair.

                  2. You keep the private key secret.

                  3. You put the public key in a CSR.

                  4. You send the CSR to the CA.

                  5. The CA issues you a certificate, embedding the public key within that certificate.

                  6. You import the certificate, which matches up with your private key to form a digital identity.

                  If you put your private key in the CSR in step 3 then the CA would get a copy of your private key in step 4.  That undermines the whole point of this process, namely, that the CA never gets your private key [1].

                  Share and Enjoy

                  Quinn “The Eskimo!”
                  Apple Developer Relations, Developer Technical Support, Core OS/Hardware
                  let myEmail = "eskimo" + "1" + "@apple.com"

                  [1] If you were happy for the CA to have a copy of your private key, you can replace this process with something much simpler:

                  1. CA generates a key pair.

                  2. CA embeds the public key in a certificate.

                  3. CA wraps private key and certificate into a PKCS#12.

                  4. CA sends you the PKCS#12.

                    • Re: Certificate-private key combo failure
                      foover Level 1 Level 1 (0 points)

                      Yeah, I assumed that openssl used the private key to generate the public.  I don't explicity send the private key to the server, only what openssl stuffs between -----BEGIN/END CERTIFICATE REQUEST-----.  The server returns a (self-signed) certificate which does have a valid public key.  Whether that key matches my private key, I don't know.  I did check the modulus and exponent of the keys and they match.  Is there more to check?  Also, the root of trust chain is installed and trusted on the target machine.  When the returned certificate is stashed in the keychain it is also trusted.  The keychain associates the certificate with the private key used to create it.  I can export that identity and import it into another keychain - but still cannot use the private key.

                       

                      I have some swift code, that I got from somewhere, which will create a CSR.  I will try that in place of openssl.

                       

                      Are there any circumstances, other than signing, which would cause the CSSMERR_CSP_OPERATION_AUTH_DENIED to be emitted?

                       

                      Thanks.

                      • Re: Certificate-private key combo failure
                        foover Level 1 Level 1 (0 points)

                        From above:

                        (1) I create an RSA key pair (SecKeyGeneratePair).

                        (2) The private key is in keychain.

                        (3-5) Using the Keychain Access app's Certificate Assistant, I create a certificate from the private key of the key pair - that's the way tool seems to work, I could not see a way to generate a certificate without selecting the private key.

                        (6) So, in my keychain I have the private key and the certificate which contains a public key - an identity.

                        I fetch the identity from the keychain (create a query, call SecItemCopyMatching, verify the typeID).

                        I use that idendityRef to get the public key (SecIdentityCopyCertificate, SecCertificateCopyPublicKey)

                        I use that idendityRef to get the private key (SecIdentityCopyPrivateKey).

                        No openssl involved.  keys and certificate created using Keychain or api calls.

                            sign - fails: CSSMERR_CSP_OPERATION_AUTH_DENIED

                            verify - not tested because it depends on signature above

                            encrypt - succeeds, returns cipherText

                            decrypt - falis: CSSMERR_CSP_OPERATION_AUTH_DENIED

                        Any suggestions of how to debug this?

                    • Re: Certificate-private key combo failure
                      foover Level 1 Level 1 (0 points)

                      I pulled code into a test application with some unit tests.  The binary is signed. The tests create a keychain file on the desktop, password protected.  The tests:

                          create Certificate Signing Request - succeeds

                          import identity - succeeds, identity is the one returned from a successful registration using the above CSR

                          sign - fails: CSSMERR_CSP_OPERATION_AUTH_DENIED

                          verify - not tested because it depends on signature above

                          encrypt - succeeds, returns cipherText

                          decrypt - falis: CSSMERR_CSP_OPERATION_AUTH_DENIED

                       

                      I am at my wits end (easy for me to reach, apparently).  The only googled-info I can find claims the CSSMERR_CSP_OPERATION_AUTH_DENIED error is due to an improperly signed binary.  Mine is signed, verified by codesign.  The keychain is unlocked (probably not necessary) when the private key is used.  What am I missing?

                       

                      Thanks for any insights.

                       

                      PS FWIW foover == pch-ivanti  Two dev account memeberships, two logins.

                        • Re: Certificate-private key combo failure
                          eskimo Apple Staff Apple Staff (12,015 points)

                          The fact that you’re getting CSSM errors is a strong indication that you’re doing this on the Mac.  Is that right?

                          If so, please check that your app (or tool, or whatever code you’re using to test this) is code signed.  The macOS keychain uses the code signature as part of its ACL mechanism; code without a code signature used to work (back before code signing was introduced) but these days it’s very much an edge case.

                          Share and Enjoy

                          Quinn “The Eskimo!”
                          Apple Developer Relations, Developer Technical Support, Core OS/Hardware
                          let myEmail = "eskimo" + "1" + "@apple.com"

                            • Re: Certificate-private key combo failure
                              foover Level 1 Level 1 (0 points)

                              Yes, it is a macOS (10.12+) command line tool that runs in the system context.

                              The binary is signed, signature verified by codesign.  The signing cert is a valid Apple-generated cert.

                              The keychain file is created by the tool and not stored in /Library/Keychains - don't know if that makes any difference.

                              A generated (SecKeyGeneratePair) RSA key pair works - data can be signed and verified.

                              The issue seems to be related to using an identity...

                                   When the private key is obtained from an identity, signing fails.  The indentity is created when a certificate is imported into the keychain and the keychain matches it with the existing private key.


                              Any suggestions for how to debug what is going on?

                               

                              Thanks.