+
+ pctx = EVP_PKEY_CTX_new_from_pkey(sctx->libctx, pubkey, sctx->propq);
+
+ if (EVP_PKEY_encapsulate_init(pctx, NULL) <= 0
+ || EVP_PKEY_encapsulate(pctx, NULL, &ctlen, NULL, &pmslen) <= 0
+ || pmslen == 0 || ctlen == 0) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+
+ pms = OPENSSL_malloc(pmslen);
+ ct = OPENSSL_malloc(ctlen);
+ if (pms == NULL || ct == NULL) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_CRYPTO_LIB);
+ goto err;
+ }
+
+ if (EVP_PKEY_encapsulate(pctx, ct, &ctlen, pms, &pmslen) <= 0) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+
+ if (gensecret) {
+ /* SSLfatal() called as appropriate in the below functions */
+ rv = ssl_gensecret(s, pms, pmslen);
+ } else {
+ /* Save premaster secret */
+ s->s3.tmp.pms = pms;
+ s->s3.tmp.pmslen = pmslen;
+ pms = NULL;
+ rv = 1;
+ }
+
+ if (rv > 0) {
+ /* Pass ownership of ct to caller */
+ *ctp = ct;
+ *ctlenp = ctlen;
+ ct = NULL;
+ }
+
+ err:
+ OPENSSL_clear_free(pms, pmslen);
+ OPENSSL_free(ct);
+ EVP_PKEY_CTX_free(pctx);
+ return rv;
+}
+
+const char *SSL_get0_group_name(SSL *s)
+{
+ SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+ unsigned int id;
+
+ if (sc == NULL)
+ return NULL;
+
+ if (SSL_CONNECTION_IS_TLS13(sc) && sc->s3.did_kex)
+ id = sc->s3.group_id;
+ else
+ id = sc->session->kex_group;
+
+ return tls1_group_id2name(s->ctx, id);
+}
+
+const char *SSL_group_to_name(SSL *s, int nid) {
+ int group_id = 0;
+ const TLS_GROUP_INFO *cinf = NULL;
+
+ /* first convert to real group id for internal and external IDs */
+ if (nid & TLSEXT_nid_unknown)
+ group_id = nid & 0xFFFF;
+ else
+ group_id = tls1_nid2group_id(nid);
+
+ /* then look up */
+ cinf = tls1_group_id_lookup(s->ctx, group_id);
+
+ if (cinf != NULL)
+ return cinf->tlsname;
+ return NULL;