+#endif
+
+/*
+ * Exports an IV from the CipherContext required to export the key
+ * state back from the unprivileged child to the privileged parent
+ * process.
+ */
+
+int
+cipher_get_keyiv_len(CipherContext *cc)
+{
+ Cipher *c = cc->cipher;
+ int ivlen;
+
+ if (c->number == SSH_CIPHER_3DES)
+ ivlen = 24;
+ else
+ ivlen = EVP_CIPHER_CTX_iv_length(&cc->evp);
+ return (ivlen);
+}
+
+void
+cipher_get_keyiv(CipherContext *cc, u_char *iv, u_int len)
+{
+ Cipher *c = cc->cipher;
+ u_char *civ = NULL;
+ int evplen;
+
+ switch (c->number) {
+ case SSH_CIPHER_SSH2:
+ case SSH_CIPHER_DES:
+ case SSH_CIPHER_BLOWFISH:
+ evplen = EVP_CIPHER_CTX_iv_length(&cc->evp);
+ if (evplen == 0)
+ return;
+ if (evplen != len)
+ fatal("%s: wrong iv length %d != %d", __func__,
+ evplen, len);
+
+#if OPENSSL_VERSION_NUMBER < 0x00907000L
+ if (c->evptype == evp_rijndael) {
+ struct ssh_rijndael_ctx *aesc;
+
+ aesc = EVP_CIPHER_CTX_get_app_data(&cc->evp);
+ if (aesc == NULL)
+ fatal("%s: no rijndael context", __func__);
+ civ = aesc->r_iv;
+ } else
+#endif
+ {
+ civ = cc->evp.iv;
+ }
+ break;
+ case SSH_CIPHER_3DES: {
+ struct ssh1_3des_ctx *desc;
+ if (len != 24)
+ fatal("%s: bad 3des iv length: %d", __func__, len);
+ desc = EVP_CIPHER_CTX_get_app_data(&cc->evp);
+ if (desc == NULL)
+ fatal("%s: no 3des context", __func__);
+ debug3("%s: Copying 3DES IV", __func__);
+ memcpy(iv, desc->k1.iv, 8);
+ memcpy(iv + 8, desc->k2.iv, 8);
+ memcpy(iv + 16, desc->k3.iv, 8);
+ return;
+ }
+ default:
+ fatal("%s: bad cipher %d", __func__, c->number);
+ }
+ memcpy(iv, civ, len);
+}
+
+void
+cipher_set_keyiv(CipherContext *cc, u_char *iv)
+{
+ Cipher *c = cc->cipher;
+ u_char *div = NULL;
+ int evplen = 0;
+
+ switch (c->number) {
+ case SSH_CIPHER_SSH2:
+ case SSH_CIPHER_DES:
+ case SSH_CIPHER_BLOWFISH:
+ evplen = EVP_CIPHER_CTX_iv_length(&cc->evp);
+ if (evplen == 0)
+ return;
+
+#if OPENSSL_VERSION_NUMBER < 0x00907000L
+ if (c->evptype == evp_rijndael) {
+ struct ssh_rijndael_ctx *aesc;
+
+ aesc = EVP_CIPHER_CTX_get_app_data(&cc->evp);
+ if (aesc == NULL)
+ fatal("%s: no rijndael context", __func__);
+ div = aesc->r_iv;
+ } else
+#endif
+ {
+ div = cc->evp.iv;
+ }
+ break;
+ case SSH_CIPHER_3DES: {
+ struct ssh1_3des_ctx *desc;
+ desc = EVP_CIPHER_CTX_get_app_data(&cc->evp);
+ if (desc == NULL)
+ fatal("%s: no 3des context", __func__);
+ debug3("%s: Installed 3DES IV", __func__);
+ memcpy(desc->k1.iv, iv, 8);
+ memcpy(desc->k2.iv, iv + 8, 8);
+ memcpy(desc->k3.iv, iv + 16, 8);
+ return;
+ }
+ default:
+ fatal("%s: bad cipher %d", __func__, c->number);
+ }
+ memcpy(div, iv, evplen);
+}
+
+#if OPENSSL_VERSION_NUMBER < 0x00907000L
+#define EVP_X_STATE(evp) &(evp).c
+#define EVP_X_STATE_LEN(evp) sizeof((evp).c)
+#else
+#define EVP_X_STATE(evp) (evp).cipher_data
+#define EVP_X_STATE_LEN(evp) (evp).cipher->ctx_size
+#endif
+
+int
+cipher_get_keycontext(CipherContext *cc, u_char *dat)
+{
+ Cipher *c = cc->cipher;
+ int plen = 0;
+
+ if (c->evptype == EVP_rc4) {
+ plen = EVP_X_STATE_LEN(cc->evp);
+ if (dat == NULL)
+ return (plen);
+ memcpy(dat, EVP_X_STATE(cc->evp), plen);
+ }
+ return (plen);
+}
+
+void
+cipher_set_keycontext(CipherContext *cc, u_char *dat)
+{
+ Cipher *c = cc->cipher;
+ int plen;
+
+ if (c->evptype == EVP_rc4) {
+ plen = EVP_X_STATE_LEN(cc->evp);
+ memcpy(EVP_X_STATE(cc->evp), dat, plen);
+ }
+}