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 #include "cert.h" 5 #include "secitem.h" 6 #include "ssl.h" 7 #include "sslimpl.h" 8 #include "sslproto.h" 9 #include "pk11func.h" 10 #include "ocsp.h" 11 12 /* NEED LOCKS IN HERE. */ 13 CERTCertificate * 14 SSL_PeerCertificate(PRFileDesc *fd) 15 { 16 sslSocket *ss; 17 18 ss = ssl_FindSocket(fd); 19 if (!ss) { 20 SSL_DBG(("%d: SSL[%d]: bad socket in PeerCertificate", 21 SSL_GETPID(), fd)); 22 return 0; 23 } 24 if (ss->opt.useSecurity && ss->sec.peerCert) { 25 return CERT_DupCertificate(ss->sec.peerCert); 26 } 27 return 0; 28 } 29 30 /* NEED LOCKS IN HERE. */ 31 CERTCertList * 32 SSL_PeerCertificateChain(PRFileDesc *fd) 33 { 34 sslSocket *ss; 35 CERTCertList *chain = NULL; 36 CERTCertificate *cert; 37 ssl3CertNode *cur; 38 39 ss = ssl_FindSocket(fd); 40 if (!ss) { 41 SSL_DBG(("%d: SSL[%d]: bad socket in PeerCertificateChain", 42 SSL_GETPID(), fd)); 43 return NULL; 44 } 45 if (!ss->opt.useSecurity || !ss->sec.peerCert) { 46 PORT_SetError(SSL_ERROR_NO_CERTIFICATE); 47 return NULL; 48 } 49 chain = CERT_NewCertList(); 50 if (!chain) { 51 return NULL; 52 } 53 cert = CERT_DupCertificate(ss->sec.peerCert); 54 if (CERT_AddCertToListTail(chain, cert) != SECSuccess) { 55 goto loser; 56 } 57 for (cur = ss->ssl3.peerCertChain; cur; cur = cur->next) { 58 cert = CERT_DupCertificate(cur->cert); 59 if (CERT_AddCertToListTail(chain, cert) != SECSuccess) { 60 goto loser; 61 } 62 } 63 return chain; 64 65 loser: 66 CERT_DestroyCertList(chain); 67 return NULL; 68 } 69 70 /* NEED LOCKS IN HERE. */ 71 CERTCertificate * 72 SSL_LocalCertificate(PRFileDesc *fd) 73 { 74 sslSocket *ss; 75 76 ss = ssl_FindSocket(fd); 77 if (!ss) { 78 SSL_DBG(("%d: SSL[%d]: bad socket in PeerCertificate", 79 SSL_GETPID(), fd)); 80 return NULL; 81 } 82 if (ss->opt.useSecurity) { 83 if (ss->sec.localCert) { 84 return CERT_DupCertificate(ss->sec.localCert); 85 } 86 if (ss->sec.ci.sid && ss->sec.ci.sid->localCert) { 87 return CERT_DupCertificate(ss->sec.ci.sid->localCert); 88 } 89 } 90 return NULL; 91 } 92 93 94 95 /* NEED LOCKS IN HERE. */ 96 SECStatus 97 SSL_SecurityStatus(PRFileDesc *fd, int *op, char **cp, int *kp0, int *kp1, 98 char **ip, char **sp) 99 { 100 sslSocket *ss; 101 const char *cipherName; 102 PRBool isDes = PR_FALSE; 103 104 ss = ssl_FindSocket(fd); 105 if (!ss) { 106 SSL_DBG(("%d: SSL[%d]: bad socket in SecurityStatus", 107 SSL_GETPID(), fd)); 108 return SECFailure; 109 } 110 111 if (cp) *cp = 0; 112 if (kp0) *kp0 = 0; 113 if (kp1) *kp1 = 0; 114 if (ip) *ip = 0; 115 if (sp) *sp = 0; 116 if (op) { 117 *op = SSL_SECURITY_STATUS_OFF; 118 } 119 120 if (ss->opt.useSecurity && ss->enoughFirstHsDone) { 121 if (ss->version < SSL_LIBRARY_VERSION_3_0) { 122 cipherName = ssl_cipherName[ss->sec.cipherType]; 123 } else { 124 cipherName = ssl3_cipherName[ss->sec.cipherType]; 125 } 126 PORT_Assert(cipherName); 127 if (cipherName) { 128 if (PORT_Strstr(cipherName, "DES")) isDes = PR_TRUE; 129 130 if (cp) { 131 *cp = PORT_Strdup(cipherName); 132 } 133 } 134 135 if (kp0) { 136 *kp0 = ss->sec.keyBits; 137 if (isDes) *kp0 = (*kp0 * 7) / 8; 138 } 139 if (kp1) { 140 *kp1 = ss->sec.secretKeyBits; 141 if (isDes) *kp1 = (*kp1 * 7) / 8; 142 } 143 if (op) { 144 if (ss->sec.keyBits == 0) { 145 *op = SSL_SECURITY_STATUS_OFF; 146 } else if (ss->sec.secretKeyBits < 90) { 147 *op = SSL_SECURITY_STATUS_ON_LOW; 148 149 } else { 150 *op = SSL_SECURITY_STATUS_ON_HIGH; 151 } 152 } 153 154 if (ip || sp) { 155 CERTCertificate *cert; 156 157 cert = ss->sec.peerCert; 158 if (cert) { 159 if (ip) { 160 *ip = CERT_NameToAscii(&cert->issuer); 161 } 162 if (sp) { 163 *sp = CERT_NameToAscii(&cert->subject); 164 } 165 } else { 166 if (ip) { 167 *ip = PORT_Strdup("no certificate"); 168 } 169 if (sp) { 170 *sp = PORT_Strdup("no certificate"); 171 } 172 } 173 } 174 } 175 176 return SECSuccess; 177 } 178 179 /************************************************************************/ 180 181 /* NEED LOCKS IN HERE. */ 182 SECStatus 183 SSL_AuthCertificateHook(PRFileDesc *s, SSLAuthCertificate func, void *arg) 184 { 185 sslSocket *ss; 186 187 ss = ssl_FindSocket(s); 188 if (!ss) { 189 SSL_DBG(("%d: SSL[%d]: bad socket in AuthCertificateHook", 190 SSL_GETPID(), s)); 191 return SECFailure; 192 } 193 194 ss->authCertificate = func; 195 ss->authCertificateArg = arg; 196 197 return SECSuccess; 198 } 199 200 /* NEED LOCKS IN HERE. */ 201 SECStatus 202 SSL_GetClientAuthDataHook(PRFileDesc *s, SSLGetClientAuthData func, 203 void *arg) 204 { 205 sslSocket *ss; 206 207 ss = ssl_FindSocket(s); 208 if (!ss) { 209 SSL_DBG(("%d: SSL[%d]: bad socket in GetClientAuthDataHook", 210 SSL_GETPID(), s)); 211 return SECFailure; 212 } 213 214 ss->getClientAuthData = func; 215 ss->getClientAuthDataArg = arg; 216 return SECSuccess; 217 } 218 219 SECStatus 220 SSL_SetClientChannelIDCallback(PRFileDesc *fd, 221 SSLClientChannelIDCallback callback, 222 void *arg) { 223 sslSocket *ss = ssl_FindSocket(fd); 224 225 if (!ss) { 226 SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetClientChannelIDCallback", 227 SSL_GETPID(), fd)); 228 return SECFailure; 229 } 230 231 ss->getChannelID = callback; 232 ss->getChannelIDArg = arg; 233 234 return SECSuccess; 235 } 236 237 #ifdef NSS_PLATFORM_CLIENT_AUTH 238 /* NEED LOCKS IN HERE. */ 239 SECStatus 240 SSL_GetPlatformClientAuthDataHook(PRFileDesc *s, 241 SSLGetPlatformClientAuthData func, 242 void *arg) 243 { 244 sslSocket *ss; 245 246 ss = ssl_FindSocket(s); 247 if (!ss) { 248 SSL_DBG(("%d: SSL[%d]: bad socket in GetPlatformClientAuthDataHook", 249 SSL_GETPID(), s)); 250 return SECFailure; 251 } 252 253 ss->getPlatformClientAuthData = func; 254 ss->getPlatformClientAuthDataArg = arg; 255 return SECSuccess; 256 } 257 #endif /* NSS_PLATFORM_CLIENT_AUTH */ 258 259 /* NEED LOCKS IN HERE. */ 260 SECStatus 261 SSL_SetPKCS11PinArg(PRFileDesc *s, void *arg) 262 { 263 sslSocket *ss; 264 265 ss = ssl_FindSocket(s); 266 if (!ss) { 267 SSL_DBG(("%d: SSL[%d]: bad socket in GetClientAuthDataHook", 268 SSL_GETPID(), s)); 269 return SECFailure; 270 } 271 272 ss->pkcs11PinArg = arg; 273 return SECSuccess; 274 } 275 276 277 /* This is the "default" authCert callback function. It is called when a 278 * certificate message is received from the peer and the local application 279 * has not registered an authCert callback function. 280 */ 281 SECStatus 282 SSL_AuthCertificate(void *arg, PRFileDesc *fd, PRBool checkSig, PRBool isServer) 283 { 284 SECStatus rv; 285 CERTCertDBHandle * handle; 286 sslSocket * ss; 287 SECCertUsage certUsage; 288 const char * hostname = NULL; 289 PRTime now = PR_Now(); 290 SECItemArray * certStatusArray; 291 292 ss = ssl_FindSocket(fd); 293 PORT_Assert(ss != NULL); 294 if (!ss) { 295 return SECFailure; 296 } 297 298 handle = (CERTCertDBHandle *)arg; 299 certStatusArray = &ss->sec.ci.sid->peerCertStatus; 300 301 if (certStatusArray->len) { 302 CERT_CacheOCSPResponseFromSideChannel(handle, ss->sec.peerCert, 303 now, &certStatusArray->items[0], 304 ss->pkcs11PinArg); 305 } 306 307 /* this may seem backwards, but isn't. */ 308 certUsage = isServer ? certUsageSSLClient : certUsageSSLServer; 309 310 rv = CERT_VerifyCert(handle, ss->sec.peerCert, checkSig, certUsage, 311 now, ss->pkcs11PinArg, NULL); 312 313 if ( rv != SECSuccess || isServer ) 314 return rv; 315 316 /* cert is OK. This is the client side of an SSL connection. 317 * Now check the name field in the cert against the desired hostname. 318 * NB: This is our only defense against Man-In-The-Middle (MITM) attacks! 319 */ 320 hostname = ss->url; 321 if (hostname && hostname[0]) 322 rv = CERT_VerifyCertName(ss->sec.peerCert, hostname); 323 else 324 rv = SECFailure; 325 if (rv != SECSuccess) 326 PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN); 327 328 return rv; 329 } 330