Skip to content

Commit fc74b88

Browse files
authored
Support forbidden certificate algorithms list in IC (#7974)
1 parent ed3bb6f commit fc74b88

File tree

7 files changed

+84
-23
lines changed

7 files changed

+84
-23
lines changed

ydb/core/driver_lib/run/kikimr_services_initializers.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,9 @@ static TInterconnectSettings GetInterconnectSettings(const NKikimrConfig::TInter
397397
break;
398398
}
399399
result.TlsAuthOnly = config.GetTlsAuthOnly();
400+
if (const auto& forbidden = config.GetForbiddenSignatureAlgorithms(); !forbidden.empty()) {
401+
result.ForbiddenSignatureAlgorithms = {forbidden.begin(), forbidden.end()};
402+
}
400403

401404
if (config.HasTCPSocketBufferSize())
402405
result.TCPSocketBufferSize = config.GetTCPSocketBufferSize();

ydb/core/protos/config.proto

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,7 @@ message TInterconnectConfig {
397397
optional bool BindOnAllAddresses = 16 [default = true];
398398
optional EEncryptionMode EncryptionMode = 17 [default = DISABLED];
399399
optional bool TlsAuthOnly = 38; // do not encrypt traffic
400+
repeated string ForbiddenSignatureAlgorithms = 50;
400401
optional bool EnforceScopeValidation = 18;
401402
optional bytes Certificate = 30; // in PEM format
402403
optional bytes PrivateKey = 31; // in PEM format

ydb/library/actors/interconnect/interconnect_common.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ namespace NActors {
4343
TString PrivateKey; // private key for the certificate in PEM format
4444
TString CaFilePath; // path to certificate authority file
4545
TString CipherList; // encryption algorithms
46+
THashSet<TString> ForbiddenSignatureAlgorithms;
4647
TDuration MessagePendingTimeout = TDuration::Seconds(1); // timeout for which messages are queued while in PendingConnection state
4748
ui64 MessagePendingSize = Max<ui64>(); // size of the queue
4849
ui32 MaxSerializedEventSize = NActors::EventMaxByteSize;

ydb/library/actors/interconnect/interconnect_stream.cpp

Lines changed: 67 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include "interconnect_stream.h"
2+
#include "interconnect_common.h"
23
#include "logging.h"
34
#include "poller_actor.h"
45
#include <library/cpp/openssl/init/init.h>
@@ -287,10 +288,12 @@ namespace NInterconnect {
287288

288289
class TSecureSocketContext::TImpl {
289290
std::unique_ptr<SSL_CTX, TDeleter> Ctx;
291+
TIntrusivePtr<NActors::TInterconnectProxyCommon> Common;
290292

291293
public:
292-
TImpl(const TString& certificate, const TString& privateKey, const TString& caFilePath,
293-
const TString& ciphers) {
294+
TImpl(TIntrusivePtr<NActors::TInterconnectProxyCommon> common)
295+
: Common(std::move(common))
296+
{
294297
int ret;
295298
InitOpenSSL();
296299
#if OPENSSL_VERSION_NUMBER < 0x10100000L
@@ -308,7 +311,7 @@ namespace NInterconnect {
308311
SSL_CTX_set_mode(*this, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
309312

310313
// apply certificates in SSL context
311-
if (certificate) {
314+
if (const TString& certificate = Common->Settings.Certificate) {
312315
std::unique_ptr<BIO, TDeleter> bio(BIO_new_mem_buf(certificate.data(), certificate.size()));
313316
Y_ABORT_UNLESS(bio);
314317

@@ -329,19 +332,19 @@ namespace NInterconnect {
329332
// we must not free memory if certificate was added successfully by SSL_CTX_add0_chain_cert
330333
}
331334
}
332-
if (privateKey) {
335+
if (const TString& privateKey = Common->Settings.PrivateKey) {
333336
std::unique_ptr<BIO, TDeleter> bio(BIO_new_mem_buf(privateKey.data(), privateKey.size()));
334337
Y_ABORT_UNLESS(bio);
335338
std::unique_ptr<EVP_PKEY, TDeleter> pkey(PEM_read_bio_PrivateKey(bio.get(), nullptr, nullptr, nullptr));
336339
Y_ABORT_UNLESS(pkey);
337340
ret = SSL_CTX_use_PrivateKey(Ctx.get(), pkey.get());
338341
Y_ABORT_UNLESS(ret == 1);
339342
}
340-
if (caFilePath) {
343+
if (const TString& caFilePath = Common->Settings.CaFilePath) {
341344
ret = SSL_CTX_load_verify_locations(Ctx.get(), caFilePath.data(), nullptr);
342345
Y_ABORT_UNLESS(ret == 1);
343346
}
344-
347+
const TString& ciphers = Common->Settings.CipherList;
345348
int success = SSL_CTX_set_cipher_list(Ctx.get(), ciphers ? ciphers.data() : "AES128-GCM-SHA256");
346349
Y_ABORT_UNLESS(success, "failed to set cipher list");
347350
}
@@ -355,34 +358,55 @@ namespace NInterconnect {
355358
return index;
356359
}
357360

361+
static int GetContextIndex() {
362+
static int index = SSL_get_ex_new_index(0, nullptr, nullptr, nullptr, nullptr);
363+
return index;
364+
}
365+
358366
private:
359367
static int Verify(int preverify, X509_STORE_CTX *ctx) {
368+
X509* const current = X509_STORE_CTX_get_current_cert(ctx);
369+
auto* const ssl = static_cast<SSL*>(X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()));
370+
auto* const errp = static_cast<TString*>(SSL_get_ex_data(ssl, GetExIndex()));
371+
auto* const secureSocketContext = static_cast<TSecureSocketContext*>(SSL_get_ex_data(ssl, GetContextIndex()));
372+
360373
if (!preverify) {
361-
X509 *badCert = X509_STORE_CTX_get_current_cert(ctx);
362374
int err = X509_STORE_CTX_get_error(ctx);
363375
int depth = X509_STORE_CTX_get_error_depth(ctx);
364-
SSL *ssl = static_cast<SSL*>(X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()));
365-
TString *errp = static_cast<TString*>(SSL_get_ex_data(ssl, GetExIndex()));
366376
char buffer[1024];
367-
X509_NAME_oneline(X509_get_subject_name(badCert), buffer, sizeof(buffer));
377+
X509_NAME_oneline(X509_get_subject_name(current), buffer, sizeof(buffer));
368378
TStringBuilder s;
369379
s << "Error during certificate validation"
370380
<< " error# " << X509_verify_cert_error_string(err)
371381
<< " depth# " << depth
372382
<< " cert# " << buffer;
373383
if (err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT) {
374-
X509_NAME_oneline(X509_get_issuer_name(badCert), buffer, sizeof(buffer));
384+
X509_NAME_oneline(X509_get_issuer_name(current), buffer, sizeof(buffer));
375385
s << " issuer# " << buffer;
376386
}
377387
*errp = s;
388+
} else if (auto& forbidden = secureSocketContext->Impl->Common->Settings.ForbiddenSignatureAlgorithms) {
389+
do {
390+
int pknid;
391+
if (X509_get_signature_info(current, nullptr, &pknid, nullptr, nullptr) != 1) {
392+
*errp = TStringBuilder() << "failed to acquire signature info";
393+
} else if (const char *ln = OBJ_nid2ln(pknid); ln && forbidden.contains(ln)) {
394+
*errp = TStringBuilder() << "forbidden signature algorithm: " << ln;
395+
} else if (const char *sn = OBJ_nid2ln(pknid); sn && forbidden.contains(sn)) {
396+
*errp = TStringBuilder() << "forbidden signature algorithm: " << sn;
397+
} else {
398+
break;
399+
}
400+
X509_STORE_CTX_set_error(ctx, X509_V_ERR_UNSUPPORTED_SIGNATURE_ALGORITHM);
401+
return 0;
402+
} while (false);
378403
}
379404
return preverify;
380405
}
381406
};
382407

383-
TSecureSocketContext::TSecureSocketContext(const TString& certificate, const TString& privateKey,
384-
const TString& caFilePath, const TString& ciphers)
385-
: Impl(new TImpl(certificate, privateKey, caFilePath, ciphers))
408+
TSecureSocketContext::TSecureSocketContext(TIntrusivePtr<NActors::TInterconnectProxyCommon> common)
409+
: Impl(new TImpl(std::move(common)))
386410
{}
387411

388412
TSecureSocketContext::~TSecureSocketContext()
@@ -395,12 +419,13 @@ namespace NInterconnect {
395419
bool WantWrite_ = false;
396420

397421
public:
398-
TImpl(SSL_CTX *ctx, int fd)
422+
TImpl(SSL_CTX *ctx, int fd, TSecureSocketContext *secureSocketContext)
399423
: Ssl(SSL_new(ctx))
400424
{
401425
Y_ABORT_UNLESS(Ssl, "SSL_new() failed");
402426
SSL_set_fd(Ssl, fd);
403427
SSL_set_ex_data(Ssl, TSecureSocketContext::TImpl::GetExIndex(), &ErrorDescription);
428+
SSL_set_ex_data(Ssl, TSecureSocketContext::TImpl::GetContextIndex(), secureSocketContext);
404429
}
405430

406431
~TImpl() {
@@ -546,18 +571,37 @@ namespace NInterconnect {
546571

547572
TString GetPeerCommonName() const {
548573
TString res;
549-
if (X509 *cert = SSL_get_peer_certificate(Ssl)) {
574+
if (std::unique_ptr<X509, void(*)(X509*)> cert{SSL_get_peer_certificate(Ssl), &X509_free}) {
550575
char buffer[256];
551576
memset(buffer, 0, sizeof(buffer));
552-
if (X509_NAME *name = X509_get_subject_name(cert)) {
577+
if (X509_NAME *name = X509_get_subject_name(cert.get())) {
553578
X509_NAME_get_text_by_NID(name, NID_commonName, buffer, sizeof(buffer));
554579
}
555-
X509_free(cert);
556580
res = TString(buffer, strnlen(buffer, sizeof(buffer)));
557581
}
558582
return res;
559583
}
560584

585+
TString GetSignatureAlgorithm() const {
586+
TString res;
587+
if (std::unique_ptr<X509, void(*)(X509*)> cert{SSL_get_peer_certificate(Ssl), &X509_free}) {
588+
int mdnid;
589+
int pknid;
590+
int secbits;
591+
if (X509_get_signature_info(cert.get(), &mdnid, &pknid, &secbits, nullptr) == 1) {
592+
res = TStringBuilder()
593+
<< "md: " << OBJ_nid2ln(mdnid)
594+
<< " pk: " << OBJ_nid2ln(pknid)
595+
<< " bits: " << secbits;
596+
} else {
597+
res = "<failed to get signature info>";
598+
}
599+
} else {
600+
res = "<failed to get peer certificate>";
601+
}
602+
return res;
603+
}
604+
561605
bool WantRead() const {
562606
return WantRead_;
563607
}
@@ -605,7 +649,7 @@ namespace NInterconnect {
605649
TSecureSocket::TSecureSocket(TStreamSocket& socket, TSecureSocketContext::TPtr context)
606650
: TStreamSocket(socket.ReleaseDescriptor())
607651
, Context(std::move(context))
608-
, Impl(new TImpl(*Context->Impl, Descriptor))
652+
, Impl(new TImpl(*Context->Impl, Descriptor, Context.get()))
609653
{}
610654

611655
TSecureSocket::~TSecureSocket()
@@ -651,6 +695,10 @@ namespace NInterconnect {
651695
return Impl->GetPeerCommonName();
652696
}
653697

698+
TString TSecureSocket::GetSignatureAlgorithm() const {
699+
return Impl->GetSignatureAlgorithm();
700+
}
701+
654702
bool TSecureSocket::WantRead() const {
655703
return Impl->WantRead();
656704
}

ydb/library/actors/interconnect/interconnect_stream.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
namespace NActors {
1818
class TPollerToken;
19+
struct TInterconnectProxyCommon;
1920
}
2021

2122
namespace NInterconnect {
@@ -82,8 +83,7 @@ namespace NInterconnect {
8283
friend class TSecureSocket;
8384

8485
public:
85-
TSecureSocketContext(const TString& certificate, const TString& privateKey, const TString& caFilePath,
86-
const TString& ciphers);
86+
TSecureSocketContext(TIntrusivePtr<NActors::TInterconnectProxyCommon> common);
8787
~TSecureSocketContext();
8888

8989
public:
@@ -121,6 +121,7 @@ namespace NInterconnect {
121121
int GetCipherBits() const;
122122
TString GetProtocolName() const;
123123
TString GetPeerCommonName() const;
124+
TString GetSignatureAlgorithm() const;
124125

125126
bool WantRead() const;
126127
bool WantWrite() const;

ydb/library/actors/interconnect/interconnect_tcp_proxy.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,7 @@ namespace NActors {
2121
, PeerNodeId(node)
2222
, DynamicPtr(dynamicPtr)
2323
, Common(std::move(common))
24-
, SecureContext(new NInterconnect::TSecureSocketContext(Common->Settings.Certificate, Common->Settings.PrivateKey,
25-
Common->Settings.CaFilePath, Common->Settings.CipherList))
24+
, SecureContext(new NInterconnect::TSecureSocketContext(Common))
2625
{
2726
Y_ABORT_UNLESS(Common);
2827
Y_ABORT_UNLESS(Common->NameserviceId);

ydb/library/actors/interconnect/interconnect_tcp_session.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1183,6 +1183,14 @@ namespace NActors {
11831183
str << x->GetPeerCommonName();
11841184
}
11851185
}
1186+
TABLER() {
1187+
TABLED() {
1188+
str << "Signature algorithm";
1189+
}
1190+
TABLED() {
1191+
str << x->GetSignatureAlgorithm();
1192+
}
1193+
}
11861194
}
11871195
TABLER() {
11881196
TABLED() { str << "AuthOnly CN"; }

0 commit comments

Comments
 (0)