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