1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 // This is a standalone server used to test Delegated Credentials
6 // (see: https://tools.ietf.org/html/draft-ietf-tls-subcerts-03).
7 //
8 // The client is expected to connect, initiate an SSL handshake (with SNI
9 // to indicate which "server" to connect to), and verify the certificate.
10 // If all is good, the client then sends one encrypted byte and receives that
11 // same byte back.
12 // This server also has the ability to "call back" another process waiting on
13 // it. That is, when the server is all set up and ready to receive connections,
14 // it will connect to a specified port and issue a simple HTTP request.
15
16 #include <iostream>
17
18 #include "TLSServer.h"
19
20 #include "sslexp.h"
21
22 using namespace mozilla;
23 using namespace mozilla::test;
24
25 struct DelegatedCertHost {
26 const char* mHostName;
27 const char* mCertName;
28 const char* mDCKeyNick;
29 bool mEnableDelegatedCredentials;
30 };
31
32 const PRUint32 kDCValidFor = 60 * 60 * 24 * 7 /* 1 week (seconds) */;
33
34 // {host, eeCert, dcCert, enableDC}
35 const DelegatedCertHost sDelegatedCertHosts[] = {
36 {"delegated-enabled.example.com", "delegated-ee", "delegated.key", true},
37 {"standard-enabled.example.com", "default-ee", "delegated.key", true},
38 {"delegated-disabled.example.com", "delegated-ee",
39 /* anything non-null */ "delegated.key", false},
40 {nullptr, nullptr, nullptr, false}};
41
DoSNISocketConfig(PRFileDesc * aFd,const SECItem * aSrvNameArr,uint32_t aSrvNameArrSize,void * aArg)42 int32_t DoSNISocketConfig(PRFileDesc* aFd, const SECItem* aSrvNameArr,
43 uint32_t aSrvNameArrSize, void* aArg) {
44 const DelegatedCertHost* host =
45 GetHostForSNI(aSrvNameArr, aSrvNameArrSize, sDelegatedCertHosts);
46 if (!host) {
47 return SSL_SNI_SEND_ALERT;
48 }
49
50 if (gDebugLevel >= DEBUG_VERBOSE) {
51 std::cerr << "Identified host " << host->mHostName << std::endl;
52 }
53
54 UniqueCERTCertificate delegatorCert(
55 PK11_FindCertFromNickname(host->mCertName, nullptr));
56 if (!delegatorCert) {
57 PrintPRError("PK11_FindCertFromNickname failed");
58 return SSL_SNI_SEND_ALERT;
59 }
60
61 UniquePK11SlotInfo slot(PK11_GetInternalKeySlot());
62 if (!slot) {
63 PrintPRError("PK11_GetInternalKeySlot failed");
64 return SSL_SNI_SEND_ALERT;
65 }
66
67 SSLExtraServerCertData extra_data = {ssl_auth_null,
68 /* Filled in by callee */ nullptr,
69 nullptr,
70 nullptr,
71 /* DC */ nullptr,
72 /* DC PrivKey */ nullptr};
73
74 UniqueSECKEYPrivateKey delegatorPriv(
75 PK11_FindKeyByDERCert(slot.get(), delegatorCert.get(), nullptr));
76 if (!delegatorPriv) {
77 PrintPRError("PK11_FindKeyByDERCert failed");
78 return SSL_SNI_SEND_ALERT;
79 }
80
81 // Find the DC keypair by the file (nick) name.
82 ScopedAutoSECItem dc;
83 UniqueSECKEYPrivateKey dcPriv;
84 if (host->mEnableDelegatedCredentials) {
85 if (gDebugLevel >= DEBUG_VERBOSE) {
86 std::cerr << "Enabling a delegated credential for host "
87 << host->mHostName << std::endl;
88 }
89
90 if (PK11_NeedLogin(slot.get())) {
91 SECStatus rv = PK11_Authenticate(slot.get(), PR_TRUE, nullptr);
92 if (rv != SECSuccess) {
93 PrintPRError("PK11_Authenticate failed");
94 return SSL_SNI_SEND_ALERT;
95 }
96 }
97 UniqueSECKEYPrivateKeyList list(PK11_ListPrivKeysInSlot(
98 slot.get(), const_cast<char*>(host->mDCKeyNick), nullptr));
99 if (!list) {
100 PrintPRError("PK11_ListPrivKeysInSlot failed");
101 return SSL_SNI_SEND_ALERT;
102 }
103 SECKEYPrivateKeyListNode* node = PRIVKEY_LIST_HEAD(list);
104
105 dcPriv.reset(SECKEY_CopyPrivateKey(node->key));
106 if (!dcPriv) {
107 PrintPRError("PK11_ListPrivKeysInSlot could not find dcPriv");
108 return SSL_SNI_SEND_ALERT;
109 }
110
111 UniqueSECKEYPublicKey dcPub(SECKEY_ConvertToPublicKey(dcPriv.get()));
112 if (!dcPub) {
113 PrintPRError("SECKEY_ConvertToPublicKey failed");
114 return SSL_SNI_SEND_ALERT;
115 }
116
117 // Create and set the DC.
118 if (SSL_DelegateCredential(delegatorCert.get(), delegatorPriv.get(),
119 dcPub.get(), ssl_sig_ecdsa_secp384r1_sha384,
120 kDCValidFor, PR_Now(), &dc) != SECSuccess) {
121 PrintPRError("SSL_DelegateCredential failed");
122 return SSL_SNI_SEND_ALERT;
123 }
124 extra_data.delegCred = &dc;
125 extra_data.delegCredPrivKey = dcPriv.get();
126
127 // The list should only have a single key.
128 PORT_Assert(PRIVKEY_LIST_END(PRIVKEY_LIST_NEXT(node), list));
129 }
130
131 if (ConfigSecureServerWithNamedCert(aFd, host->mCertName, nullptr, nullptr,
132 &extra_data) != SECSuccess) {
133 PrintPRError("ConfigSecureServerWithNamedCert failed");
134 return SSL_SNI_SEND_ALERT;
135 }
136
137 return 0;
138 }
139
main(int argc,char * argv[])140 int main(int argc, char* argv[]) {
141 return StartServer(argc, argv, DoSNISocketConfig, nullptr);
142 }
143