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