Skip to content

Commit

Permalink
src: move more x509 to ncrypto
Browse files Browse the repository at this point in the history
Signed-off-by: James M Snell <[email protected]>
  • Loading branch information
jasnell committed Jan 27, 2025
1 parent a2ec037 commit 5843486
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 62 deletions.
71 changes: 71 additions & 0 deletions deps/ncrypto/ncrypto.cc
Original file line number Diff line number Diff line change
Expand Up @@ -915,6 +915,18 @@ BIOPointer X509View::toDER() const {
return bio;
}

const X509Name X509View::getSubjectName() const {
ClearErrorOnReturn clearErrorOnReturn;
if (cert_ == nullptr) return {};
return X509Name(X509_get_subject_name(cert_));
}

const X509Name X509View::getIssuerName() const {
ClearErrorOnReturn clearErrorOnReturn;
if (cert_ == nullptr) return {};
return X509Name(X509_get_issuer_name(cert_));
}

BIOPointer X509View::getSubject() const {
ClearErrorOnReturn clearErrorOnReturn;
if (cert_ == nullptr) return {};
Expand Down Expand Up @@ -3831,4 +3843,63 @@ DataPointer hashDigest(const Buffer<const unsigned char>& buf,
return data.resize(result_size);
}

// ============================================================================

X509Name::X509Name() : name_(nullptr), total_(0) {}

X509Name::X509Name(const X509_NAME* name)
: name_(name), total_(X509_NAME_entry_count(name)) {}

X509Name::Iterator::Iterator(const X509Name& name, int pos)
: name_(name), loc_(pos) {}

X509Name::Iterator& X509Name::Iterator::operator++() {
++loc_;
return *this;
}

X509Name::Iterator::operator bool() const {
return loc_ < name_.total_;
}

bool X509Name::Iterator::operator==(const Iterator& other) const {
return loc_ == other.loc_;
}

bool X509Name::Iterator::operator!=(const Iterator& other) const {
return loc_ != other.loc_;
}

std::pair<std::string, std::string> X509Name::Iterator::operator*() const {
if (loc_ == name_.total_) return {{}, {}};

X509_NAME_ENTRY* entry = X509_NAME_get_entry(name_, loc_);
if (entry == nullptr) [[unlikely]]
return {{}, {}};

ASN1_OBJECT* name = X509_NAME_ENTRY_get_object(entry);
ASN1_STRING* value = X509_NAME_ENTRY_get_data(entry);

if (name == nullptr || value == nullptr) [[unlikely]] {
return {{}, {}};
}

int nid = OBJ_obj2nid(name);
std::string name_str;
if (nid != NID_undef) {
name_str = std::string(OBJ_nid2sn(nid));
} else {
char buf[80];
OBJ_obj2txt(buf, sizeof(buf), name, 0);
name_str = std::string(buf);
}

unsigned char* value_str;
int value_str_size = ASN1_STRING_to_UTF8(&value_str, value);

return {
std::move(name_str),
std::string(reinterpret_cast<const char*>(value_str), value_str_size)};
}

} // namespace ncrypto
39 changes: 39 additions & 0 deletions deps/ncrypto/ncrypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -934,6 +934,43 @@ class SSLPointer final {
DeleteFnPtr<SSL, SSL_free> ssl_;
};

class X509Name final {
public:
X509Name();
explicit X509Name(const X509_NAME* name);
NCRYPTO_DISALLOW_COPY_AND_MOVE(X509Name)

inline operator const X509_NAME*() const { return name_; }
inline operator bool() const { return name_ != nullptr; }
inline const X509_NAME* get() const { return name_; }
inline size_t size() const { return total_; }

class Iterator final {
public:
Iterator(const X509Name& name, int pos);
Iterator(const Iterator& other) = default;
Iterator(Iterator&& other) = default;
Iterator& operator=(const Iterator& other) = delete;
Iterator& operator=(Iterator&& other) = delete;
Iterator& operator++();
operator bool() const;
bool operator==(const Iterator& other) const;
bool operator!=(const Iterator& other) const;
std::pair<std::string, std::string> operator*() const;

private:
const X509Name& name_;
int loc_;
};

inline Iterator begin() const { return Iterator(*this, 0); }
inline Iterator end() const { return Iterator(*this, total_); }

private:
const X509_NAME* name_;
int total_;
};

class X509View final {
public:
static X509View From(const SSLPointer& ssl);
Expand All @@ -955,6 +992,8 @@ class X509View final {
BIOPointer toPEM() const;
BIOPointer toDER() const;

const X509Name getSubjectName() const;
const X509Name getIssuerName() const;
BIOPointer getSubject() const;
BIOPointer getSubjectAltName() const;
BIOPointer getIssuer() const;
Expand Down
75 changes: 13 additions & 62 deletions src/crypto/crypto_x509.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ using ncrypto::ClearErrorOnReturn;
using ncrypto::DataPointer;
using ncrypto::ECKeyPointer;
using ncrypto::SSLPointer;
using ncrypto::X509Name;
using ncrypto::X509Pointer;
using ncrypto::X509View;
using v8::Array;
Expand Down Expand Up @@ -92,6 +93,11 @@ void Fingerprint(const FunctionCallbackInfo<Value>& args) {
}
}

MaybeLocal<String> ToV8Value(Environment* env, std::string_view val) {
return String::NewFromUtf8(
env->isolate(), val.data(), NewStringType::kNormal, val.size());
}

MaybeLocal<Value> ToV8Value(Local<Context> context, BIOPointer&& bio) {
if (!bio) [[unlikely]]
return {};
Expand All @@ -106,51 +112,6 @@ MaybeLocal<Value> ToV8Value(Local<Context> context, BIOPointer&& bio) {
return ret;
}

MaybeLocal<Value> ToV8Value(Local<Context> context, const ASN1_OBJECT* obj) {
// If OpenSSL knows the type, use the short name of the type as the key, and
// the numeric representation of the type's OID otherwise.
int nid = OBJ_obj2nid(obj);
char buf[80];
const char* str;
if (nid != NID_undef) {
str = OBJ_nid2sn(nid);
CHECK_NOT_NULL(str);
} else {
OBJ_obj2txt(buf, sizeof(buf), obj, true);
str = buf;
}

Local<Value> result;
if (!String::NewFromUtf8(context->GetIsolate(), str).ToLocal(&result)) {
return {};
}
return result;
}

MaybeLocal<Value> ToV8Value(Local<Context> context, const ASN1_STRING* str) {
// The previous implementation used X509_NAME_print_ex, which escapes some
// characters in the value. The old implementation did not decode/unescape
// values correctly though, leading to ambiguous and incorrect
// representations. The new implementation only converts to Unicode and does
// not escape anything.
unsigned char* value_str;
int value_str_size = ASN1_STRING_to_UTF8(&value_str, str);
if (value_str_size < 0) [[unlikely]] {
return Undefined(context->GetIsolate());
}
DataPointer free_value_str(value_str, value_str_size);

Local<Value> result;
if (!String::NewFromUtf8(context->GetIsolate(),
reinterpret_cast<const char*>(value_str),
NewStringType::kNormal,
value_str_size)
.ToLocal(&result)) {
return {};
}
return result;
}

MaybeLocal<Value> ToV8Value(Local<Context> context, const BIOPointer& bio) {
if (!bio) [[unlikely]]
return {};
Expand Down Expand Up @@ -594,14 +555,9 @@ bool Set(Environment* env,
// Convert an X509_NAME* into a JavaScript object.
// Each entry of the name is converted into a property of the object.
// The property value may be a single string or an array of strings.
template <X509_NAME* get_name(const X509*)>
static MaybeLocal<Value> GetX509NameObject(Environment* env,
const X509View& cert) {
X509_NAME* name = get_name(cert.get());
CHECK_NOT_NULL(name);

int cnt = X509_NAME_entry_count(name);
CHECK_GE(cnt, 0);
const X509Name& name) {
if (!name) return {};

Local<Value> v8_name;
Local<Value> v8_value;
Expand All @@ -610,14 +566,9 @@ static MaybeLocal<Value> GetX509NameObject(Environment* env,
Object::New(env->isolate(), Null(env->isolate()), nullptr, nullptr, 0);
if (result.IsEmpty()) return {};

for (int i = 0; i < cnt; i++) {
X509_NAME_ENTRY* entry = X509_NAME_get_entry(name, i);
CHECK_NOT_NULL(entry);

if (!ToV8Value(env->context(), X509_NAME_ENTRY_get_object(entry))
.ToLocal(&v8_name) ||
!ToV8Value(env->context(), X509_NAME_ENTRY_get_data(entry))
.ToLocal(&v8_value)) {
for (auto i : name) {
if (!ToV8Value(env, i.first).ToLocal(&v8_name) ||
!ToV8Value(env, i.second).ToLocal(&v8_value)) {
return {};
}

Expand Down Expand Up @@ -727,11 +678,11 @@ MaybeLocal<Object> X509ToObject(Environment* env, const X509View& cert) {
if (!Set<Value>(env,
info,
env->subject_string(),
GetX509NameObject<X509_get_subject_name>(env, cert)) ||
GetX509NameObject(env, cert.getSubjectName())) ||
!Set<Value>(env,
info,
env->issuer_string(),
GetX509NameObject<X509_get_issuer_name>(env, cert)) ||
GetX509NameObject(env, cert.getIssuerName())) ||
!Set<Value>(env,
info,
env->subjectaltname_string(),
Expand Down

0 comments on commit 5843486

Please sign in to comment.