SECStatus SSL_ExportKeyingMaterial(PRFileDesc *fd, const char *label, unsigned int labelLen, PRBool hasContext, const unsigned char *context, unsigned int contextLen, unsigned char *out, unsigned int outLen) { sslSocket *ss; unsigned char *val = NULL; unsigned int valLen, i; SECStatus rv = SECFailure; ss = ssl_FindSocket(fd); if (!ss) { SSL_DBG(("%d: SSL[%d]: bad socket in ExportKeyingMaterial", SSL_GETPID(), fd)); return SECFailure; } if (!label || !labelLen || !out || !outLen || (hasContext && (!context || !contextLen))) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) { return tls13_Exporter(ss, ss->ssl3.hs.exporterSecret, label, labelLen, context, hasContext ? contextLen : 0, out, outLen); } if (hasContext && contextLen > MAX_CONTEXT_LEN) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } /* construct PRF arguments */ valLen = SSL3_RANDOM_LENGTH * 2; if (hasContext) { valLen += 2 /* PRUint16 length */ + contextLen; } val = PORT_Alloc(valLen); if (!val) { return SECFailure; } i = 0; PORT_Memcpy(val + i, &ss->ssl3.hs.client_random.rand, SSL3_RANDOM_LENGTH); i += SSL3_RANDOM_LENGTH; PORT_Memcpy(val + i, &ss->ssl3.hs.server_random.rand, SSL3_RANDOM_LENGTH); i += SSL3_RANDOM_LENGTH; if (hasContext) { val[i++] = contextLen >> 8; val[i++] = contextLen; PORT_Memcpy(val + i, context, contextLen); i += contextLen; } PORT_Assert(i == valLen); /* Allow TLS keying material to be exported sooner, when the master * secret is available and we have sent ChangeCipherSpec. */ ssl_GetSpecReadLock(ss); if (!ss->ssl3.cwSpec->master_secret && !ss->ssl3.cwSpec->msItem.len) { PORT_SetError(SSL_ERROR_HANDSHAKE_NOT_COMPLETED); rv = SECFailure; } else { rv = ssl3_TLSPRFWithMasterSecret(ss, ss->ssl3.cwSpec, label, labelLen, val, valLen, out, outLen); } ssl_ReleaseSpecReadLock(ss); PORT_ZFree(val, valLen); return rv; }
SECStatus SSL_ExportKeyingMaterial(PRFileDesc *fd, const char *label, unsigned int labelLen, PRBool hasContext, const unsigned char *context, unsigned int contextLen, unsigned char *out, unsigned int outLen) { sslSocket *ss; unsigned char *val = NULL; unsigned int valLen, i; SECStatus rv = SECFailure; ss = ssl_FindSocket(fd); if (!ss) { SSL_DBG(("%d: SSL[%d]: bad socket in ExportKeyingMaterial", SSL_GETPID(), fd)); return SECFailure; } ssl_GetRecvBufLock(ss); ssl_GetSSL3HandshakeLock(ss); if (ss->version < SSL_LIBRARY_VERSION_3_1_TLS) { PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_VERSION); ssl_ReleaseSSL3HandshakeLock(ss); ssl_ReleaseRecvBufLock(ss); return SECFailure; } valLen = SSL3_RANDOM_LENGTH * 2; if (hasContext) { valLen += 2 + contextLen; } val = PORT_Alloc(valLen); if (!val) { ssl_ReleaseSSL3HandshakeLock(ss); ssl_ReleaseRecvBufLock(ss); return SECFailure; } i = 0; PORT_Memcpy(val + i, &ss->ssl3.hs.client_random.rand, SSL3_RANDOM_LENGTH); i += SSL3_RANDOM_LENGTH; PORT_Memcpy(val + i, &ss->ssl3.hs.server_random.rand, SSL3_RANDOM_LENGTH); i += SSL3_RANDOM_LENGTH; if (hasContext) { val[i++] = contextLen >> 8; val[i++] = contextLen; PORT_Memcpy(val + i, context, contextLen); i += contextLen; } PORT_Assert(i == valLen); ssl_GetSpecReadLock(ss); if (!ss->ssl3.cwSpec->master_secret && !ss->ssl3.cwSpec->msItem.len) { PORT_SetError(SSL_ERROR_HANDSHAKE_NOT_COMPLETED); rv = SECFailure; } else { rv = ssl3_TLSPRFWithMasterSecret(ss->ssl3.cwSpec, label, labelLen, val, valLen, out, outLen); } ssl_ReleaseSpecReadLock(ss); ssl_ReleaseSSL3HandshakeLock(ss); ssl_ReleaseRecvBufLock(ss); PORT_ZFree(val, valLen); return rv; }