+CERT *ssl_cert_dup(CERT *cert)
+ {
+ CERT *ret;
+ int i;
+
+ ret = (CERT *)OPENSSL_malloc(sizeof(CERT));
+ if (ret == NULL)
+ {
+ SSLerr(SSL_F_SSL_CERT_DUP, ERR_R_MALLOC_FAILURE);
+ return(NULL);
+ }
+
+ memset(ret, 0, sizeof(CERT));
+
+ ret->key = &ret->pkeys[cert->key - &cert->pkeys[0]];
+ /* or ret->key = ret->pkeys + (cert->key - cert->pkeys),
+ * if you find that more readable */
+
+ ret->valid = cert->valid;
+ ret->mask = cert->mask;
+ ret->export_mask = cert->export_mask;
+
+#ifndef OPENSSL_NO_RSA
+ if (cert->rsa_tmp != NULL)
+ {
+ RSA_up_ref(cert->rsa_tmp);
+ ret->rsa_tmp = cert->rsa_tmp;
+ }
+ ret->rsa_tmp_cb = cert->rsa_tmp_cb;
+#endif
+
+#ifndef OPENSSL_NO_DH
+ if (cert->dh_tmp != NULL)
+ {
+ ret->dh_tmp = DHparams_dup(cert->dh_tmp);
+ if (ret->dh_tmp == NULL)
+ {
+ SSLerr(SSL_F_SSL_CERT_DUP, ERR_R_DH_LIB);
+ goto err;
+ }
+ if (cert->dh_tmp->priv_key)
+ {
+ BIGNUM *b = BN_dup(cert->dh_tmp->priv_key);
+ if (!b)
+ {
+ SSLerr(SSL_F_SSL_CERT_DUP, ERR_R_BN_LIB);
+ goto err;
+ }
+ ret->dh_tmp->priv_key = b;
+ }
+ if (cert->dh_tmp->pub_key)
+ {
+ BIGNUM *b = BN_dup(cert->dh_tmp->pub_key);
+ if (!b)
+ {
+ SSLerr(SSL_F_SSL_CERT_DUP, ERR_R_BN_LIB);
+ goto err;
+ }
+ ret->dh_tmp->pub_key = b;
+ }
+ }
+ ret->dh_tmp_cb = cert->dh_tmp_cb;
+#endif
+
+#ifndef OPENSSL_NO_ECDH
+ if (cert->ecdh_tmp)
+ {
+ ret->ecdh_tmp = EC_KEY_dup(cert->ecdh_tmp);
+ if (ret->ecdh_tmp == NULL)
+ {
+ SSLerr(SSL_F_SSL_CERT_DUP, ERR_R_EC_LIB);
+ goto err;
+ }
+ }
+ ret->ecdh_tmp_cb = cert->ecdh_tmp_cb;
+#endif
+
+ for (i = 0; i < SSL_PKEY_NUM; i++)
+ {
+ if (cert->pkeys[i].x509 != NULL)
+ {
+ ret->pkeys[i].x509 = cert->pkeys[i].x509;
+ CRYPTO_add(&ret->pkeys[i].x509->references, 1,
+ CRYPTO_LOCK_X509);
+ }
+
+ if (cert->pkeys[i].privatekey != NULL)
+ {
+ ret->pkeys[i].privatekey = cert->pkeys[i].privatekey;
+ CRYPTO_add(&ret->pkeys[i].privatekey->references, 1,
+ CRYPTO_LOCK_EVP_PKEY);
+
+ switch(i)
+ {
+ /* If there was anything special to do for
+ * certain types of keys, we'd do it here.
+ * (Nothing at the moment, I think.) */
+
+ case SSL_PKEY_RSA_ENC:
+ case SSL_PKEY_RSA_SIGN:
+ /* We have an RSA key. */
+ break;
+
+ case SSL_PKEY_DSA_SIGN:
+ /* We have a DSA key. */
+ break;
+
+ case SSL_PKEY_DH_RSA:
+ case SSL_PKEY_DH_DSA:
+ /* We have a DH key. */
+ break;
+
+ case SSL_PKEY_ECC:
+ /* We have an ECC key */
+ break;
+
+ default:
+ /* Can't happen. */
+ SSLerr(SSL_F_SSL_CERT_DUP, SSL_R_LIBRARY_BUG);
+ }
+ }
+ }
+
+ /* ret->extra_certs *should* exist, but currently the own certificate
+ * chain is held inside SSL_CTX */
+
+ ret->references=1;
+
+ return(ret);
+
+#ifndef OPENSSL_NO_DH /* avoid 'unreferenced label' warning if OPENSSL_NO_DH is defined */
+err:
+#endif
+#ifndef OPENSSL_NO_RSA
+ if (ret->rsa_tmp != NULL)
+ RSA_free(ret->rsa_tmp);
+#endif
+#ifndef OPENSSL_NO_DH
+ if (ret->dh_tmp != NULL)
+ DH_free(ret->dh_tmp);
+#endif
+#ifndef OPENSSL_NO_ECDH
+ if (ret->ecdh_tmp != NULL)
+ EC_KEY_free(ret->ecdh_tmp);
+#endif
+
+ for (i = 0; i < SSL_PKEY_NUM; i++)
+ {
+ if (ret->pkeys[i].x509 != NULL)
+ X509_free(ret->pkeys[i].x509);
+ if (ret->pkeys[i].privatekey != NULL)
+ EVP_PKEY_free(ret->pkeys[i].privatekey);
+ }
+
+ return NULL;
+ }
+
+