Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Request for CSR generation examples using C API #26

Closed
danielcongxu opened this issue Feb 14, 2022 · 20 comments
Closed

Request for CSR generation examples using C API #26

danielcongxu opened this issue Feb 14, 2022 · 20 comments
Labels
documentation Improvements or additions to documentation

Comments

@danielcongxu
Copy link

Hi,

Could you add a C API that instructs the way of CSR generation using TPM provider even though there's an existing one in openssl executable?

@gotthardp gotthardp added the documentation Improvements or additions to documentation label Feb 14, 2022
@gotthardp
Copy link
Contributor

gotthardp commented Feb 14, 2022

Yeah, I may add one or two C examples, but the code is exactly the same as for generating a "standard" CSR, except you have to load the providers first.
The code for a standard CSR is e.g. here: https://stackoverflow.com/questions/38949576/how-to-programmatically-create-a-certificate-signing-request-csr

@danielcongxu
Copy link
Author

@gotthardp

Thank you for the prompt reply! And I still have some questions:

(1) In addition to loading tpm provder first, do I have to explicitly associate the loaded provider with the comming openssl operations for csr generation?
(2) Request DN such as cmmonName, courtyName could be configured with X509_REQ_set_subject_name without specifying a configuration file, which is stated in rsa_createak_x509_csr.sh ==> -new -config testcert.conf?
(3) Is there a way to generate csr with exact key-handle using opessl C API as the command: openssl req -provider tpm2 -new -config testcert.conf -key handle:${HANDLE} -out testcsr.pem? From the example you provided above, I see a path to private key file is required.

@danielcongxu
Copy link
Author

@gotthardp

In detail, if I already obtained an AK handle after createak gets called, what's the proper way to generate csr with such an AK handle using openssl API. The example is about private key outside of TPM

@gotthardp
Copy link
Contributor

The openssl 3.0 has libctx. If you do OSSL_PROVIDER_load with a NULL libctx, the default context is used. In such case you should be able to use the usual PEM_read_PrivateKey, because the association is done via the internal default context.
Alternatively you may create your own context, OSSL_PROVIDER_load into that context and then specify it explicitly in an alternative PEM_read_PrivateKey_ex.

Concerning the key path: when the TPM provider is loaded the handle:0x80000000 is a valid path that can be used with the EVP_PKEY loading functions.

@danielcongxu
Copy link
Author

@gotthardp

Thank you! Then the property order to generate csr would be as the following:

  1. OSSL_PROVIDER_load the tpm2 provider
  2. PEM_read_PrivateKey(handle:, NULL, NULL, NULL) to construct a EVP_PKEY object
  3. X509_REQ_set functions to set previous EVP_PKEY object, DN and etc., which fills the certificate related fields.
  4. X509_REQ_sign to generate the ultimate csr.

Is that correct?

@gotthardp
Copy link
Contributor

Yes, this looks good to me.

@danielcongxu
Copy link
Author

Yes, this looks good to me.

Sincere appreciation, have a nice day:)

@gotthardp
Copy link
Contributor

If it doesn't work as expected, just let me know.

I will keep this issue open until I write some more C examples.

@danielcongxu
Copy link
Author

Sure, I will.

@danielcongxu
Copy link
Author

@gotthardp

From your proposal, I had a line of "FILE *fp = fopen("handle:0x81110003", "r");" where 0x81110003 is an existing key handle retrieved from "tpm2_getcap handles-persistent".

Out of expectation, the fp results in a NULL pointer. Could you help to confirm it's the proper way to load key into EVP_PKEY object?

@gotthardp
Copy link
Contributor

Oops, sorry. You cannot use the standard fopen. Please try https://www.openssl.org/docs/man3.0/man7/ossl_store.html instead. There is an example at the end of that page for CERT, but there are similar functions for a PKEY too.

@danielcongxu
Copy link
Author

@gotthardp

Oh, I see. It uses a while loop to consistently output he data read from the store. But if I tried with OSSL_STORE_INFO_get0_PKEY and return a EVP_PKEY object, do I still need the while loop? If so, how do I get the ultimate EVP_PKEY object considering the temporary EVP_PKEY object inside each iteration?

@danielcongxu
Copy link
Author

Oops, sorry. You cannot use the standard fopen. Please try https://www.openssl.org/docs/man3.0/man7/ossl_store.html instead. There is an example at the end of that page for CERT, but there are similar functions for a PKEY too.

I remote the while loop since from my purpose is to get the exact one key, and that seems to succeed.

@gotthardp
Copy link
Contributor

The OSSL_STORE_INFO_get0_PKEY returns a pointer to an openssl internal object, while OSSL_STORE_INFO_get1_PKEY returns a pointer to a duplicate object. You may definitely take the duplicate object and exit the while loop.

@danielcongxu
Copy link
Author

danielcongxu commented Feb 17, 2022

@gotthardp

So the EVP_PKEY loading code should looks as follows:

EVP_PKEY *pub_key = NULL;
while (!OSSL_STORE_eof(ctx)) {
OSSL_STORE_INFO *info = OSSL_STORE_load(ctx);
pub_key = OSSL_STORE_INFO_get1_PKEY(info);
break;
}

Does it follow the expectation?

@gotthardp
Copy link
Contributor

Plus on the beginning:

OSSL_STORE_CTX *ctx = OSSL_STORE_open("handle:0x81110003");

and at the end

OSSL_STORE_close(ctx);

plus you should probably handle the errors, i.e. call break only when the PKEY is successfully loaded.

@danielcongxu
Copy link
Author

Thanks!

@danielcongxu
Copy link
Author

Hi @gotthardp,

I was getting to programmatically to generate csr using tpm2-openssl. Now I'm getting error from OSSL_STORE_load, and from the stack the culprit seems to be this line of code: https://github.com/openssl/openssl/blob/89cd17a031e022211684eb7eb41190cf1910f9fa/crypto/store/store_result.c#L209

The provider retrieved from keymgmt is not the one loaded from OSSL_STORE_LOAD. Since the key used for signing CSR creates before OSSL_STORE_LOAD, does it mean I have to follow such an order, aka OSSL_STORE_LOAD ==> Generate TPM key ==> Generate CSR with OpenSSL?

Also I've tested against the mentioned order, and the application failed on key generation, specifically tpm2_createprimary.

Look forward to your insignts, thank you

@danielcongxu
Copy link
Author

Here's my code snippet:

if ((ctx = OSSL_STORE_open(tpm_key_path.c_str(), nullptr, nullptr, nullptr, nullptr)) == nullptr) {
goto CLEANUP;
}

while (!OSSL_STORE_eof(ctx)) {
if ((info = OSSL_STORE_load(ctx)) == nullptr) {
goto CLEANUP;
}
if ((p_key = OSSL_STORE_INFO_get1_PKEY(info)) == nullptr) {
goto CLEANUP;
}
// Only break on key gets loaded successfully
break;
}

@danielcongxu
Copy link
Author

@gotthardp

The aforementioned issues gets resolved by creating my own specific context (aka OSSL_LIB_CTX). Loading provider as well as opening store with such a context, then the OSSL_STORE_load returns success.

I took some time to see why the provider check on store_result.c:199 not work as expected by stepping into openssl code, although failed to achieved much progress. Anyway thanks for your help, and I think this issue could be closed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to documentation
Projects
None yet
Development

No branches or pull requests

2 participants