mirror of
https://github.com/dart-lang/sdk
synced 2024-10-03 00:45:16 +00:00
[dart:io] Adds X509Certificate.der and X509Certificate.pem
fixes #33115 Change-Id: I7ccf5998b23e936040fe65792824f09d3f494cf7 Reviewed-on: https://dart-review.googlesource.com/55505 Commit-Queue: Zach Anderson <zra@google.com> Reviewed-by: Ben Konyi <bkonyi@google.com>
This commit is contained in:
parent
62ffedefdd
commit
e7495e427c
|
@ -15,6 +15,10 @@
|
|||
* Marked `MirrorsUsed` as deprecated. The mirrors library is no longer
|
||||
supported by dart2js, and `MirrorsUsed` only affected dart2js.
|
||||
|
||||
* `dart:io`
|
||||
* Added `X509Certificate.der`, `X509Certificate.pem`, and
|
||||
`X509Certificate.sha1`.
|
||||
|
||||
### Dart VM
|
||||
|
||||
### Tool Changes
|
||||
|
|
|
@ -169,6 +169,9 @@ namespace bin {
|
|||
V(SynchronousSocket_ReadList, 4) \
|
||||
V(SynchronousSocket_WriteList, 4) \
|
||||
V(SystemEncodingToString, 1) \
|
||||
V(X509_Der, 1) \
|
||||
V(X509_Pem, 1) \
|
||||
V(X509_Sha1, 1) \
|
||||
V(X509_Subject, 1) \
|
||||
V(X509_Issuer, 1) \
|
||||
V(X509_StartValidity, 1) \
|
||||
|
|
|
@ -202,6 +202,33 @@ class _X509CertificateImpl extends NativeFieldWrapperClass1
|
|||
// This is done by WrappedX509 in secure_socket.cc.
|
||||
_X509CertificateImpl();
|
||||
|
||||
Uint8List _cachedDer;
|
||||
Uint8List get _der native "X509_Der";
|
||||
Uint8List get der {
|
||||
if (_cachedDer == null) {
|
||||
_cachedDer = _der;
|
||||
}
|
||||
return _cachedDer;
|
||||
}
|
||||
|
||||
String _cachedPem;
|
||||
String get _pem native "X509_Pem";
|
||||
String get pem {
|
||||
if (_cachedPem == null) {
|
||||
_cachedPem = _pem;
|
||||
}
|
||||
return _cachedPem;
|
||||
}
|
||||
|
||||
Uint8List _cachedSha1;
|
||||
Uint8List get _sha1 native "X509_Sha1";
|
||||
Uint8List get sha1 {
|
||||
if (_cachedSha1 == null) {
|
||||
_cachedSha1 = _sha1;
|
||||
}
|
||||
return _cachedSha1;
|
||||
}
|
||||
|
||||
String get subject native "X509_Subject";
|
||||
String get issuer native "X509_Issuer";
|
||||
DateTime get startValidity {
|
||||
|
|
|
@ -125,6 +125,16 @@ void FUNCTION_NAME(SecurityContext_UseCertificateChainBytes)(
|
|||
"Secure Sockets unsupported on this platform"));
|
||||
}
|
||||
|
||||
void FUNCTION_NAME(X509_Der)(Dart_NativeArguments args) {
|
||||
Dart_ThrowException(DartUtils::NewDartArgumentError(
|
||||
"Secure Sockets unsupported on this platform"));
|
||||
}
|
||||
|
||||
void FUNCTION_NAME(X509_Sha1)(Dart_NativeArguments args) {
|
||||
Dart_ThrowException(DartUtils::NewDartArgumentError(
|
||||
"Secure Sockets unsupported on this platform"));
|
||||
}
|
||||
|
||||
void FUNCTION_NAME(X509_Subject)(Dart_NativeArguments args) {
|
||||
Dart_ThrowException(DartUtils::NewDartArgumentError(
|
||||
"Secure Sockets unsupported on this platform"));
|
||||
|
@ -145,6 +155,11 @@ void FUNCTION_NAME(X509_EndValidity)(Dart_NativeArguments args) {
|
|||
"Secure Sockets unsupported on this platform"));
|
||||
}
|
||||
|
||||
void FUNCTION_NAME(X509_Pem)(Dart_NativeArguments args) {
|
||||
Dart_ThrowException(DartUtils::NewDartArgumentError(
|
||||
"Secure Sockets unsupported on this platform"));
|
||||
}
|
||||
|
||||
class SSLFilter {
|
||||
public:
|
||||
static CObject* ProcessFilterRequest(const CObjectArray& request);
|
||||
|
|
|
@ -647,6 +647,101 @@ static X509* GetX509Certificate(Dart_NativeArguments args) {
|
|||
return certificate;
|
||||
}
|
||||
|
||||
Dart_Handle X509Helper::GetDer(Dart_NativeArguments args) {
|
||||
X509* certificate = GetX509Certificate(args);
|
||||
// When the second argument is NULL, i2d_X509() returns the length of the
|
||||
// DER encoded cert in bytes.
|
||||
intptr_t length = i2d_X509(certificate, NULL);
|
||||
Dart_Handle cert_handle = Dart_NewTypedData(Dart_TypedData_kUint8, length);
|
||||
if (Dart_IsError(cert_handle)) {
|
||||
Dart_PropagateError(cert_handle);
|
||||
}
|
||||
Dart_TypedData_Type typ;
|
||||
void* dart_cert_bytes = NULL;
|
||||
Dart_Handle status =
|
||||
Dart_TypedDataAcquireData(cert_handle, &typ, &dart_cert_bytes, &length);
|
||||
if (Dart_IsError(status)) {
|
||||
Dart_PropagateError(status);
|
||||
}
|
||||
|
||||
// When the the second argument points to a non-NULL buffer address,
|
||||
// i2d_X509 fills that buffer with the DER encoded cert data and increments
|
||||
// the buffer pointer.
|
||||
unsigned char* tmp = static_cast<unsigned char*>(dart_cert_bytes);
|
||||
length = i2d_X509(certificate, &tmp);
|
||||
if (length < 0) {
|
||||
Dart_TypedDataReleaseData(cert_handle);
|
||||
SecureSocketUtils::ThrowIOException(
|
||||
-1, "TlsException", "Failed to get certificate bytes", NULL);
|
||||
// SecureSocketUtils::ThrowIOException() does not return.
|
||||
}
|
||||
|
||||
status = Dart_TypedDataReleaseData(cert_handle);
|
||||
if (Dart_IsError(status)) {
|
||||
Dart_PropagateError(status);
|
||||
}
|
||||
return cert_handle;
|
||||
}
|
||||
|
||||
Dart_Handle X509Helper::GetPem(Dart_NativeArguments args) {
|
||||
X509* certificate = GetX509Certificate(args);
|
||||
BIO* cert_bio = BIO_new(BIO_s_mem());
|
||||
intptr_t status = PEM_write_bio_X509(cert_bio, certificate);
|
||||
if (status == 0) {
|
||||
BIO_free(cert_bio);
|
||||
SecureSocketUtils::ThrowIOException(
|
||||
-1, "TlsException", "Failed to write certificate to PEM", NULL);
|
||||
// SecureSocketUtils::ThrowIOException() does not return.
|
||||
}
|
||||
|
||||
BUF_MEM* mem = NULL;
|
||||
BIO_get_mem_ptr(cert_bio, &mem);
|
||||
Dart_Handle pem_string = Dart_NewStringFromUTF8(
|
||||
reinterpret_cast<const uint8_t*>(mem->data), mem->length);
|
||||
BIO_free(cert_bio);
|
||||
if (Dart_IsError(pem_string)) {
|
||||
Dart_PropagateError(pem_string);
|
||||
}
|
||||
|
||||
return pem_string;
|
||||
}
|
||||
|
||||
Dart_Handle X509Helper::GetSha1(Dart_NativeArguments args) {
|
||||
unsigned char sha1_bytes[EVP_MAX_MD_SIZE];
|
||||
X509* certificate = GetX509Certificate(args);
|
||||
const EVP_MD* hash_type = EVP_sha1();
|
||||
|
||||
unsigned int sha1_size;
|
||||
intptr_t status = X509_digest(certificate, hash_type, sha1_bytes, &sha1_size);
|
||||
if (status == 0) {
|
||||
SecureSocketUtils::ThrowIOException(
|
||||
-1, "TlsException", "Failed to compute certificate's sha1", NULL);
|
||||
// SecureSocketUtils::ThrowIOException() does not return.
|
||||
}
|
||||
|
||||
Dart_Handle sha1_handle = Dart_NewTypedData(Dart_TypedData_kUint8, sha1_size);
|
||||
if (Dart_IsError(sha1_handle)) {
|
||||
Dart_PropagateError(sha1_handle);
|
||||
}
|
||||
|
||||
Dart_TypedData_Type typ;
|
||||
void* dart_sha1_bytes;
|
||||
intptr_t length;
|
||||
Dart_Handle result =
|
||||
Dart_TypedDataAcquireData(sha1_handle, &typ, &dart_sha1_bytes, &length);
|
||||
if (Dart_IsError(result)) {
|
||||
Dart_PropagateError(result);
|
||||
}
|
||||
|
||||
memmove(dart_sha1_bytes, sha1_bytes, length);
|
||||
|
||||
result = Dart_TypedDataReleaseData(sha1_handle);
|
||||
if (Dart_IsError(result)) {
|
||||
Dart_PropagateError(result);
|
||||
}
|
||||
return sha1_handle;
|
||||
}
|
||||
|
||||
Dart_Handle X509Helper::GetSubject(Dart_NativeArguments args) {
|
||||
X509* certificate = GetX509Certificate(args);
|
||||
X509_NAME* subject = X509_get_subject_name(certificate);
|
||||
|
@ -784,6 +879,18 @@ void FUNCTION_NAME(SecurityContext_TrustBuiltinRoots)(
|
|||
context->TrustBuiltinRoots();
|
||||
}
|
||||
|
||||
void FUNCTION_NAME(X509_Der)(Dart_NativeArguments args) {
|
||||
Dart_SetReturnValue(args, X509Helper::GetDer(args));
|
||||
}
|
||||
|
||||
void FUNCTION_NAME(X509_Pem)(Dart_NativeArguments args) {
|
||||
Dart_SetReturnValue(args, X509Helper::GetPem(args));
|
||||
}
|
||||
|
||||
void FUNCTION_NAME(X509_Sha1)(Dart_NativeArguments args) {
|
||||
Dart_SetReturnValue(args, X509Helper::GetSha1(args));
|
||||
}
|
||||
|
||||
void FUNCTION_NAME(X509_Subject)(Dart_NativeArguments args) {
|
||||
Dart_SetReturnValue(args, X509Helper::GetSubject(args));
|
||||
}
|
||||
|
|
|
@ -102,6 +102,9 @@ class SSLCertContext : public ReferenceCounted<SSLCertContext> {
|
|||
|
||||
class X509Helper : public AllStatic {
|
||||
public:
|
||||
static Dart_Handle GetDer(Dart_NativeArguments args);
|
||||
static Dart_Handle GetPem(Dart_NativeArguments args);
|
||||
static Dart_Handle GetSha1(Dart_NativeArguments args);
|
||||
static Dart_Handle GetSubject(Dart_NativeArguments args);
|
||||
static Dart_Handle GetIssuer(Dart_NativeArguments args);
|
||||
static Dart_Handle GetStartValidity(Dart_NativeArguments args);
|
||||
|
|
|
@ -342,6 +342,15 @@ abstract class RawSecureSocket implements RawSocket {
|
|||
abstract class X509Certificate {
|
||||
external factory X509Certificate._();
|
||||
|
||||
/// The DER encoded bytes of the certificate.
|
||||
Uint8List get der;
|
||||
|
||||
/// The PEM encoded String of the certificate.
|
||||
String get pem;
|
||||
|
||||
/// The SHA1 hash of the certificate.
|
||||
Uint8List get sha1;
|
||||
|
||||
String get subject;
|
||||
String get issuer;
|
||||
DateTime get startValidity;
|
||||
|
|
|
@ -41,10 +41,27 @@ Future<SecureServerSocket> startEchoServer() {
|
|||
});
|
||||
}
|
||||
|
||||
void checkServerCertificate(X509Certificate serverCert) {
|
||||
String serverCertString = serverCert.pem;
|
||||
String certFile =
|
||||
new File(localFile('certificates/server_chain.pem')).readAsStringSync();
|
||||
Expect.isTrue(certFile.contains(serverCertString));
|
||||
|
||||
// Computed with:
|
||||
// openssl x509 -noout -sha1 -fingerprint -in certificates/server_chain.pem
|
||||
List<int> serverSha1 = <int>[
|
||||
0xB3, 0x01, 0xCB, 0x7E, 0x6F, 0xEF, 0xBE, 0xEF, //
|
||||
0x75, 0x6D, 0xA8, 0x80, 0x60, 0xA8, 0x5D, 0x6F, //
|
||||
0xC4, 0xED, 0xCD, 0x48, //
|
||||
];
|
||||
Expect.listEquals(serverSha1, serverCert.sha1);
|
||||
}
|
||||
|
||||
Future testClient(server) {
|
||||
return SecureSocket
|
||||
.connect(HOST, server.port, context: clientContext)
|
||||
.then((socket) {
|
||||
checkServerCertificate(socket.peerCertificate);
|
||||
socket.write("Hello server.");
|
||||
socket.close();
|
||||
return socket.fold(<int>[], (message, data) => message..addAll(data)).then(
|
||||
|
|
Loading…
Reference in a new issue