-
Notifications
You must be signed in to change notification settings - Fork 361
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
Added cert generation and verification APIs for attested TLS #1761
Conversation
e029a6f
to
b8424b2
Compare
if (n) | ||
*dest = '\0'; | ||
|
||
return ret; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mikbras @soccerGB @CodeMonkeyLeet @paulcallen @gupta-ak
The need to implement and review oe_strncpy is one of the reasons why corelibc is more trouble than it is worth.
This implementation of oe_strncpy looks correct - copy at most n characters from src to dst - a bounded string-copy.
However this implementation is incorrect because, counterintuitively, strncpy has different semantics according to the C standard. strncpy requires that the destination be padded with null characters if the src contains less that n characters.
Copies the first num characters of source to destination. If the end of the source C string (which is signaled by a null-character) is found before num characters have been copied, destination is padded with zeros until a total of num characters have been written to it.
From Ansi C Rationale
strncpy was initially introduced into the C library to deal with fixed-length name fields in structures such as directory entries. Such fields are not used in the same way as strings: the trailing null is unnecessary for a maximum-length field, and setting trailing bytes for shorter names to null assures efficient field-wise comparisons. strncpy is not by origin a ``bounded strcpy,'' and the Committee has preferred to recognize existing practice rather than alter the function to better suit it to such use.
C libraries take great pains to implement the standard; no matter how counter-intuitive the standard is. Take for example MUSL's implementation of which strncpy forwards to:
https://github.com/microsoft/openenclave/blob/fe0c6af59d1d3ec038c47cda52555cdf351b10f8/3rdparty/musl/musl/src/string/stpncpy.c#L10-L29
MUSL's strncpy follows the C standard by null-padding the destination bytes. Additionally, when used as a glibc replacement, it does glibc compatible optimizations.
Since crypto is a key component in writing secure code, we need to shy away from writing new code in the hot path. Instead we need to rely on battle tested code like MUSL or GLIBC (along with their security fixes).
If we start implementing libc functions, when we are already using a full fledged libc implementation like MUSL, we ought to lock down each C function we implement rigorously with tests and prove to ourselves that we are standards compliant. At this moment I don't see rigorous tests for corelibc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree with Anand here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1. If we have a POSIX name we must adhere to the standard. strncpy as specified in the standard is dangerous since it does not guarantee null termination (as explained at the link Anand cites). As such, if we make oe_strncpy be public, then it should probably be marked as deprecated or unsafe or something, so it will generate warnings if an app tries to use it. strncpy_s is the safer API to use.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is strncpy was added for the purpose getting mbedtls built on top of corelibc, where once we starting building mbedtls on top of the musl, this direct corelibc dependency will be removed thus the concern raised will be gone because this strncpy will become no longer needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you open an issue to keep track of removing this strncpy implementation or fixing it to be libc compliant before the next release? Otherwise, we would increase the risk of unpredictable behavior/potential security vulnerability.
bors try |
bors try |
tryNot awaiting review |
tryBuild failed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should probably have a full review on the new additions to the public API surface.
@@ -161,6 +161,13 @@ OE_STATIC_ASSERT(sizeof(oe_report_header_t) == 16); | |||
OE_STATIC_ASSERT( | |||
OE_OFFSETOF(oe_report_header_t, report) == sizeof(oe_report_header_t)); | |||
|
|||
// ISO(1).ANSI(2).USA(840).Microsoft(113556).ACC(10).Classes(103).Subclass(1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment doesn't match the OID we're using. (Classes is 1, not 103)
Have we registered this with the OID range owners in MS to avoid collisions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mismatched class id fixed.
Still figuring out how to register this OID
if (n) | ||
*dest = '\0'; | ||
|
||
return ret; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OE_RAISE(OE_INVALID_PARAMETER); | ||
|
||
/* Allocate memory for the certificate */ | ||
if (!(crt = mbedtls_calloc(1, sizeof(mbedtls_x509_crt)))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Personally I think it's bad for a core OE file to directly hard code mbedTLS specific API calls instead of going through an abstraction layer. I thought that was being addressed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This cert.c is part of the crypto implementation for the enclave, which depends solely on the mbedtls library.
Before that dependency was replaced/removed, we will have to keep it this way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't parse the last sentence in your reply. Do you mean "Until that is done"? meaning it's future work to fix this? Or what? I still maintain its bad to call mbedtls APIs directly from OE core code.
if (n) | ||
*dest = '\0'; | ||
|
||
return ret; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1. If we have a POSIX name we must adhere to the standard. strncpy as specified in the standard is dangerous since it does not guarantee null termination (as explained at the link Anand cites). As such, if we make oe_strncpy be public, then it should probably be marked as deprecated or unsafe or something, so it will generate warnings if an app tries to use it. strncpy_s is the safer API to use.
ef7d6e0
to
960a17b
Compare
include/openenclave/enclave.h
Outdated
@@ -724,6 +724,76 @@ oe_enclave_t* oe_get_enclave(void); | |||
*/ | |||
oe_result_t oe_random(void* data, size_t size); | |||
|
|||
/** | |||
* oe_generate_attestation_cert. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't use abbreviations ("cert") in non-POSIX API names.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks for spotting this.
Renamed to
oe_generate_attestation_certificate
oe_free_attestation_certificate
oe_verify_attestation_certificate
include/openenclave/enclave.h
Outdated
/** | ||
* oe_generate_attestation_cert. | ||
* | ||
* This function generates a self-signed x509 certificate with an embedded |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
x509 -> X.509
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks for spotting this. Fixed.
include/openenclave/enclave.h
Outdated
* This function generates a self-signed x509 certificate with an embedded | ||
* quote from the underlying enclave. | ||
* | ||
* @param[in] subject_name a string contains contain an X.509 distinguished |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"contains contain" -> "containing"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks for spotting this. Fixed.
* See RFC5280 (https://tools.ietf.org/html/rfc5280) specification for details. | ||
* Example value "CN=Open Enclave SDK,O=OESDK TLS,C=US" | ||
* | ||
* @param[in] private_key a private key used to sign this certificate |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: some lines end in period (740, 742) and some don't (739, 741). Be consistent throughout this file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks for spotting this. Fixed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit is not yet fixed. See line 742
include/openenclave/enclave.h
Outdated
/** | ||
* oe_verify_attestation_cert | ||
* | ||
* This function preform a custom validation on the input certificate. This |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"preform" -> "perform"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks for spotting this. Fixed.
include/openenclave/enclave.h
Outdated
* @param[in] cert_in_der_len size of certificate buffer above | ||
* @param[in] enclave_identity_callback callback routine for custom identity | ||
* checking | ||
* @param[in] arg optional argument |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what is "arg" used for? "optional argument" is not a helpful description
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rephrased to
- @param[in] arg an optional context pointer argument specified by the
- application when setting callback
include/openenclave/enclave.h
Outdated
* oe_verify_attestation_cert | ||
* | ||
* This function preform a custom validation on the input certificate. This | ||
* validation includes extracting a quote extension from the certificate before |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the term "quote" is SGX specific and does not belong in the doxygen comments at all, unless used in an example where it's clear it's using SGX as the example
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good point.
I replaced "quote" with "attestation evidence".
include/openenclave/host.h
Outdated
/** | ||
* oe_verify_attestation_cert | ||
* | ||
* This function preform a custom validation on the input certificate. This |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comments in host.h as I added into enclave.h
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addressed
4313fed
to
043eede
Compare
all feedback were addressed
bors r+ |
1761: Added cert generation and verification APIs for attested TLS r=soccerGB a=soccerGB This is certification generation (oe_gen_tls_cert) and verification (oe_verify_tls_cert) part of attested tls feature. #1325 I am hoping to preliminary feedback whether the implementation of those two new APIs impacts other features/refactoring activities under construction. End-2-end test and samples will come in a separate PR once its depending components (socket) are ready. Co-authored-by: Cheng-mean Liu <[email protected]>
Build failed |
tests/tls_apis/enc/CMakeLists.txt
Outdated
|
||
target_include_directories(tls_enc PRIVATE | ||
${CMAKE_CURRENT_BINARY_DIR} | ||
${PROJECT_SOURCE_DIR}/include/openenclave/corelibc) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is corelibc part of the includes if you're already linking with oelibc? You should have the headers from musl.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is an internal test case, where a couple of internal oe_* api, defined in oecorelibc, were used. That's why corelibc path was included.
In the upcoming external same code, it will solely base on the musl headers.
tests/tls_apis/enc/enc.cpp
Outdated
/* Only map CHAR_BIT out of limits.h to scope potential standard definition | ||
* name conflicts in enclave sources. | ||
*/ | ||
#if !defined(CHAR_BIT) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think you need to do this if you remove the corelibc includes.
bors try |
tryBuild failed |
2ebf7eb
to
a66362f
Compare
bors r+ |
1761: Added cert generation and verification APIs for attested TLS r=soccerGB a=soccerGB This is certification generation (oe_gen_tls_cert) and verification (oe_verify_tls_cert) part of attested tls feature. #1325 I am hoping to preliminary feedback whether the implementation of those two new APIs impacts other features/refactoring activities under construction. End-2-end test and samples will come in a separate PR once its depending components (socket) are ready. Co-authored-by: Cheng-mean Liu <[email protected]>
Build succeeded |
1818: Remove OE_USE_LIBSGX on verifying report. r=soccerGB a=gupta-ak This allows remote quote verification without `OE_USE_LIBSGX`. It's essentially a piece of PR #1575 to unblock Cheng-mean's PR #1761. A way to test this is to run the report test with a pre-generated report. That test should now pass. Co-authored-by: Akash Gupta <[email protected]>
sig_oid, sig_oid_len, sig, sig_len ) ); | ||
|
||
if( len > (size_t)( c2 - buf ) ) | ||
return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); | ||
/* |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@soccerGB The previous version returned MBEDTLS_ERR_ASN1_BUF_TOO_SMALL.
I cannot spot where the new version returns the same error code.
int rc = 0; | ||
|
||
/* Clear the implementation */ | ||
if (impl) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If an impl already exists, then shouldn't we be cleaning up contents of the impl rather than just doing memset?
@@ -665,7 +707,7 @@ oe_result_t oe_cert_verify( | |||
} | |||
|
|||
/* Check for invalid chain parameter */ | |||
if (!_cert_chain_is_valid(chain_impl)) | |||
if (chain && !_cert_chain_is_valid(chain_impl)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be chain_impl &&
?
*/ | ||
c = tmp_buf + sizeof( tmp_buf ); | ||
c = buf + size; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These look like changes to mbedtls itself. Are they being contributed back upstream to the master mbedtls? If not, why not? If so, what's the link to the pull request or commit?
OE_RAISE(OE_INVALID_PARAMETER); | ||
|
||
/* Allocate memory for the certificate */ | ||
if (!(crt = mbedtls_calloc(1, sizeof(mbedtls_x509_crt)))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't parse the last sentence in your reply. Do you mean "Until that is done"? meaning it's future work to fix this? Or what? I still maintain its bad to call mbedtls APIs directly from OE core code.
#define ISSUER_NAME "CN=Open Enclave SDK,O=OESDK TLS,C=UK" | ||
#define SUBJECT_NAME ISSUER_NAME | ||
#define DATE_NOT_VALID_BEFORE "20190501000000" | ||
#define DATE_NOT_VALID_AFTER "20501231235959" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's bad to hard code any timestamps in code, as opposed to in admin-configurable policy.
* See RFC5280 (https://tools.ietf.org/html/rfc5280) specification for details. | ||
* Example value "CN=Open Enclave SDK,O=OESDK TLS,C=US" | ||
* | ||
* @param[in] private_key a private key used to sign this certificate |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit is not yet fixed. See line 742
* Free the given cert | ||
* @param[in] cert If not NULL, the buffer to free. | ||
*/ | ||
void oe_free_attestation_certificate(uint8_t* cert); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style comment: In Microsoft public headers and sample code, we try to avoid abbreviations not just in method names, but also variable/parameter names. "cert" should be expanded to "certificate" in 755, 756, 760, 762, etc., for consistency with the method name. (Acronyms on the other hand are fine, so "der" is perfectly fine in 794.) There are a very small number of exceptions where abbreviations are ok. Those include "app" and "arg" (which is used in this file and is ok.)
- **Host Side** | ||
1. Create an enclave | ||
2. Issue an ecall (get_tls_cert) into enclave for getting a self-signed certificate embedded with an quote of the enclave | ||
3. Once the certificate is received, call oe_verify_attestation_cert to verify the certificate and quote |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cert -> certificate (and same in oe_generate_attestation_cert on line 12)
#define TEST_RSA_KEY 1 | ||
#define SKIP_RETURN_CODE 2 | ||
|
||
// This is the identity validation callback. An TLS connecting party (client or |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
grammar nit: "An TLS" -> "A TLS"
"./cert_%s.der", | ||
test_type == TEST_RSA_KEY ? "rsa" : "ec"); | ||
OE_TRACE_INFO( | ||
"Host: Log quote embedded certificate to file: [%s]\n", filename); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe the term "quote" is SGX specific. Use platform agnostic terms in trace output from non-SGX-specific code
This is certification generation (oe_gen_tls_cert) and verification (oe_verify_tls_cert) part of attested tls feature.
#1325
I am hoping to preliminary feedback whether the implementation of those two new APIs impacts other features/refactoring activities under construction.
End-2-end test and samples will come in a separate PR once its depending components (socket) are ready.