diff --git a/ext/openssl/extconf.rb b/ext/openssl/extconf.rb
index c2bf9d6..d3ae224 100644
--- a/ext/openssl/extconf.rb
+++ b/ext/openssl/extconf.rb
@@ -66,8 +66,15 @@
 
 Logging::message "=== Checking for OpenSSL features... ===\n"
 # compile options
-have_func("SSLv2_method")
-have_func("SSLv3_method")
+
+# check OPENSSL_NO_{SSL2,SSL3_METHOD} macro: on some environment, these symbols
+# exist even if compiled with no-ssl2 or no-ssl3-method.
+unless have_macro("OPENSSL_NO_SSL2", "openssl/opensslconf.h")
+  have_func("SSLv2_method")
+end
+unless have_macro("OPENSSL_NO_SSL3_METHOD", "openssl/opensslconf.h")
+  have_func("SSLv3_method")
+end
 have_func("TLSv1_1_method")
 have_func("TLSv1_2_method")
 have_func("RAND_egd")
@@ -90,6 +97,7 @@
 have_func("X509_NAME_hash_old")
 have_func("X509_STORE_CTX_get0_current_crl")
 have_func("X509_STORE_set_verify_cb")
+have_func("i2d_ASN1_SET_ANY")
 OpenSSL.check_func_or_macro("SSL_set_tlsext_host_name", "openssl/ssl.h")
 have_struct_member("CRYPTO_THREADID", "ptr", "openssl/crypto.h")
 
@@ -102,7 +110,7 @@
 have_func("EC_curve_nist2nid")
 have_func("X509_REVOKED_dup")
 have_func("X509_STORE_CTX_get0_store")
-have_func("SSL_is_server");
+have_func("SSL_is_server")
 have_func("SSL_CTX_set_alpn_select_cb")
 OpenSSL.check_func_or_macro("SSL_CTX_set1_curves_list", "openssl/ssl.h")
 OpenSSL.check_func_or_macro("SSL_CTX_set_ecdh_auto", "openssl/ssl.h")
diff --git a/ext/openssl/openssl_missing.h b/ext/openssl/openssl_missing.h
index 2cb03ec..6aef62a 100644
--- a/ext/openssl/openssl_missing.h
+++ b/ext/openssl/openssl_missing.h
@@ -45,6 +45,11 @@ int HMAC_CTX_copy(HMAC_CTX *out, HMAC_CTX *in);
 #  define X509_STORE_set_verify_cb X509_STORE_set_verify_cb_func
 #endif
 
+#if !defined(HAVE_I2D_ASN1_SET_ANY)
+#  define i2d_ASN1_SET_ANY(sk, x) i2d_ASN1_SET_OF_ASN1_TYPE((sk), (x), \
+		i2d_ASN1_TYPE, V_ASN1_SET, V_ASN1_UNIVERSAL, 0)
+#endif
+
 /* added in 1.0.2 */
 #if !defined(HAVE_CRYPTO_MEMCMP)
 int CRYPTO_memcmp(const volatile void * volatile in_a, const volatile void * volatile in_b, size_t len);
diff --git a/ext/openssl/ossl_pkey_dh.c b/ext/openssl/ossl_pkey_dh.c
index 550f48c..84246ff 100644
--- a/ext/openssl/ossl_pkey_dh.c
+++ b/ext/openssl/ossl_pkey_dh.c
@@ -327,16 +327,18 @@ static VALUE
 ossl_dh_to_der(VALUE self)
 {
     EVP_PKEY *pkey;
+    DH *dh;
     unsigned char *p;
     long len;
     VALUE str;
 
     GetPKeyDH(self, pkey);
-    if((len = i2d_DHparams(EVP_PKEY_get0_DH(pkey), NULL)) <= 0)
+    dh = EVP_PKEY_get0_DH(pkey);
+    if((len = i2d_DHparams(dh, NULL)) <= 0)
 	ossl_raise(eDHError, NULL);
     str = rb_str_new(0, len);
     p = (unsigned char *)RSTRING_PTR(str);
-    if(i2d_DHparams(EVP_PKEY_get0_DH(pkey), &p) < 0)
+    if(i2d_DHparams(dh, &p) < 0)
 	ossl_raise(eDHError, NULL);
     ossl_str_adjust(str, p);
 
diff --git a/ext/openssl/ossl_pkey_dsa.c b/ext/openssl/ossl_pkey_dsa.c
index 840e142..9051c69 100644
--- a/ext/openssl/ossl_pkey_dsa.c
+++ b/ext/openssl/ossl_pkey_dsa.c
@@ -325,6 +325,7 @@ static VALUE
 ossl_dsa_export(int argc, VALUE *argv, VALUE self)
 {
     EVP_PKEY *pkey;
+    DSA *dsa;
     BIO *out;
     const EVP_CIPHER *ciph = NULL;
     char *passwd = NULL;
@@ -344,14 +345,15 @@ ossl_dsa_export(int argc, VALUE *argv, VALUE self)
     if (!(out = BIO_new(BIO_s_mem()))) {
 	ossl_raise(eDSAError, NULL);
     }
-    if (dsa_has_private(EVP_PKEY_get0_DSA(pkey))) {
-	if (!PEM_write_bio_DSAPrivateKey(out, EVP_PKEY_get0_DSA(pkey), ciph,
-					 NULL, 0, ossl_pem_passwd_cb, passwd)){
+    dsa = EVP_PKEY_get0_DSA(pkey);
+    if (dsa_has_private(dsa)) {
+	if (!PEM_write_bio_DSAPrivateKey(out, dsa, ciph, NULL, 0,
+					 ossl_pem_passwd_cb, passwd)){
 	    BIO_free(out);
 	    ossl_raise(eDSAError, NULL);
 	}
     } else {
-	if (!PEM_write_bio_DSA_PUBKEY(out, EVP_PKEY_get0_DSA(pkey))) {
+	if (!PEM_write_bio_DSA_PUBKEY(out, dsa)) {
 	    BIO_free(out);
 	    ossl_raise(eDSAError, NULL);
 	}
@@ -372,21 +374,23 @@ static VALUE
 ossl_dsa_to_der(VALUE self)
 {
     EVP_PKEY *pkey;
+    DSA *dsa;
     int (*i2d_func)_((DSA*, unsigned char**));
     unsigned char *p;
     long len;
     VALUE str;
 
     GetPKeyDSA(self, pkey);
-    if(dsa_has_private(EVP_PKEY_get0_DSA(pkey)))
+    dsa = EVP_PKEY_get0_DSA(pkey);
+    if(dsa_has_private(dsa))
 	i2d_func = (int(*)_((DSA*,unsigned char**)))i2d_DSAPrivateKey;
     else
 	i2d_func = i2d_DSA_PUBKEY;
-    if((len = i2d_func(EVP_PKEY_get0_DSA(pkey), NULL)) <= 0)
+    if((len = i2d_func(dsa, NULL)) <= 0)
 	ossl_raise(eDSAError, NULL);
     str = rb_str_new(0, len);
     p = (unsigned char *)RSTRING_PTR(str);
-    if(i2d_func(EVP_PKEY_get0_DSA(pkey), &p) < 0)
+    if(i2d_func(dsa, &p) < 0)
 	ossl_raise(eDSAError, NULL);
     ossl_str_adjust(str, p);
 
diff --git a/ext/openssl/ossl_pkey_rsa.c b/ext/openssl/ossl_pkey_rsa.c
index b5c03f4..223699d 100644
--- a/ext/openssl/ossl_pkey_rsa.c
+++ b/ext/openssl/ossl_pkey_rsa.c
@@ -320,6 +320,7 @@ static VALUE
 ossl_rsa_export(int argc, VALUE *argv, VALUE self)
 {
     EVP_PKEY *pkey;
+    RSA *rsa;
     BIO *out;
     const EVP_CIPHER *ciph = NULL;
     char *passwd = NULL;
@@ -341,14 +342,15 @@ ossl_rsa_export(int argc, VALUE *argv, VALUE self)
     if (!(out = BIO_new(BIO_s_mem()))) {
 	ossl_raise(eRSAError, NULL);
     }
-    if (rsa_has_private(EVP_PKEY_get0_RSA(pkey))) {
-	if (!PEM_write_bio_RSAPrivateKey(out, EVP_PKEY_get0_RSA(pkey), ciph,
-					 NULL, 0, ossl_pem_passwd_cb, passwd)) {
+    rsa = EVP_PKEY_get0_RSA(pkey);
+    if (rsa_has_private(rsa)) {
+	if (!PEM_write_bio_RSAPrivateKey(out, rsa, ciph, NULL, 0,
+					 ossl_pem_passwd_cb, passwd)) {
 	    BIO_free(out);
 	    ossl_raise(eRSAError, NULL);
 	}
     } else {
-	if (!PEM_write_bio_RSA_PUBKEY(out, EVP_PKEY_get0_RSA(pkey))) {
+	if (!PEM_write_bio_RSA_PUBKEY(out, rsa)) {
 	    BIO_free(out);
 	    ossl_raise(eRSAError, NULL);
 	}
@@ -368,28 +370,30 @@ static VALUE
 ossl_rsa_to_der(VALUE self)
 {
     EVP_PKEY *pkey;
+    RSA *rsa;
     int (*i2d_func)_((const RSA*, unsigned char**));
     unsigned char *p;
     long len;
     VALUE str;
 
     GetPKeyRSA(self, pkey);
-    if(rsa_has_private(EVP_PKEY_get0_RSA(pkey)))
+    rsa = EVP_PKEY_get0_RSA(pkey);
+    if(rsa_has_private(rsa))
 	i2d_func = i2d_RSAPrivateKey;
     else
 	i2d_func = (int (*)(const RSA*, unsigned char**))i2d_RSA_PUBKEY;
-    if((len = i2d_func(EVP_PKEY_get0_RSA(pkey), NULL)) <= 0)
+    if((len = i2d_func(rsa, NULL)) <= 0)
 	ossl_raise(eRSAError, NULL);
     str = rb_str_new(0, len);
     p = (unsigned char *)RSTRING_PTR(str);
-    if(i2d_func(EVP_PKEY_get0_RSA(pkey), &p) < 0)
+    if(i2d_func(rsa, &p) < 0)
 	ossl_raise(eRSAError, NULL);
     ossl_str_adjust(str, p);
 
     return str;
 }
 
-#define ossl_rsa_buf_size(pkey) (RSA_size(EVP_PKEY_get0_RSA(pkey))+16)
+#define ossl_rsa_buf_size(rsa) (RSA_size(rsa)+16)
 
 /*
  * call-seq:
@@ -403,17 +407,18 @@ static VALUE
 ossl_rsa_public_encrypt(int argc, VALUE *argv, VALUE self)
 {
     EVP_PKEY *pkey;
+    RSA *rsa;
     int buf_len, pad;
     VALUE str, buffer, padding;
 
     GetPKeyRSA(self, pkey);
+    rsa = EVP_PKEY_get0_RSA(pkey);
     rb_scan_args(argc, argv, "11", &buffer, &padding);
     pad = (argc == 1) ? RSA_PKCS1_PADDING : NUM2INT(padding);
     StringValue(buffer);
-    str = rb_str_new(0, ossl_rsa_buf_size(pkey));
+    str = rb_str_new(0, ossl_rsa_buf_size(rsa));
     buf_len = RSA_public_encrypt(RSTRING_LENINT(buffer), (unsigned char *)RSTRING_PTR(buffer),
-				 (unsigned char *)RSTRING_PTR(str), EVP_PKEY_get0_RSA(pkey),
-				 pad);
+				 (unsigned char *)RSTRING_PTR(str), rsa, pad);
     if (buf_len < 0) ossl_raise(eRSAError, NULL);
     rb_str_set_len(str, buf_len);
 
@@ -432,17 +437,18 @@ static VALUE
 ossl_rsa_public_decrypt(int argc, VALUE *argv, VALUE self)
 {
     EVP_PKEY *pkey;
+    RSA *rsa;
     int buf_len, pad;
     VALUE str, buffer, padding;
 
     GetPKeyRSA(self, pkey);
+    rsa = EVP_PKEY_get0_RSA(pkey);
     rb_scan_args(argc, argv, "11", &buffer, &padding);
     pad = (argc == 1) ? RSA_PKCS1_PADDING : NUM2INT(padding);
     StringValue(buffer);
-    str = rb_str_new(0, ossl_rsa_buf_size(pkey));
+    str = rb_str_new(0, ossl_rsa_buf_size(rsa));
     buf_len = RSA_public_decrypt(RSTRING_LENINT(buffer), (unsigned char *)RSTRING_PTR(buffer),
-				 (unsigned char *)RSTRING_PTR(str), EVP_PKEY_get0_RSA(pkey),
-				 pad);
+				 (unsigned char *)RSTRING_PTR(str), rsa, pad);
     if (buf_len < 0) ossl_raise(eRSAError, NULL);
     rb_str_set_len(str, buf_len);
 
@@ -461,20 +467,21 @@ static VALUE
 ossl_rsa_private_encrypt(int argc, VALUE *argv, VALUE self)
 {
     EVP_PKEY *pkey;
+    RSA *rsa;
     int buf_len, pad;
     VALUE str, buffer, padding;
 
     GetPKeyRSA(self, pkey);
+    rsa = EVP_PKEY_get0_RSA(pkey);
     if (!rsa_is_private(self, EVP_PKEY_get0_RSA(pkey))) {
 	ossl_raise(eRSAError, "private key needed.");
     }
     rb_scan_args(argc, argv, "11", &buffer, &padding);
     pad = (argc == 1) ? RSA_PKCS1_PADDING : NUM2INT(padding);
     StringValue(buffer);
-    str = rb_str_new(0, ossl_rsa_buf_size(pkey));
+    str = rb_str_new(0, ossl_rsa_buf_size(rsa));
     buf_len = RSA_private_encrypt(RSTRING_LENINT(buffer), (unsigned char *)RSTRING_PTR(buffer),
-				  (unsigned char *)RSTRING_PTR(str), EVP_PKEY_get0_RSA(pkey),
-				  pad);
+				  (unsigned char *)RSTRING_PTR(str), rsa, pad);
     if (buf_len < 0) ossl_raise(eRSAError, NULL);
     rb_str_set_len(str, buf_len);
 
@@ -493,20 +500,21 @@ static VALUE
 ossl_rsa_private_decrypt(int argc, VALUE *argv, VALUE self)
 {
     EVP_PKEY *pkey;
+    RSA *rsa;
     int buf_len, pad;
     VALUE str, buffer, padding;
 
     GetPKeyRSA(self, pkey);
-    if (!rsa_is_private(self, EVP_PKEY_get0_RSA(pkey))) {
+    rsa = EVP_PKEY_get0_RSA(pkey);
+    if (!rsa_is_private(self, rsa)) {
 	ossl_raise(eRSAError, "private key needed.");
     }
     rb_scan_args(argc, argv, "11", &buffer, &padding);
     pad = (argc == 1) ? RSA_PKCS1_PADDING : NUM2INT(padding);
     StringValue(buffer);
-    str = rb_str_new(0, ossl_rsa_buf_size(pkey));
+    str = rb_str_new(0, ossl_rsa_buf_size(rsa));
     buf_len = RSA_private_decrypt(RSTRING_LENINT(buffer), (unsigned char *)RSTRING_PTR(buffer),
-				  (unsigned char *)RSTRING_PTR(str), EVP_PKEY_get0_RSA(pkey),
-				  pad);
+				  (unsigned char *)RSTRING_PTR(str), rsa, pad);
     if (buf_len < 0) ossl_raise(eRSAError, NULL);
     rb_str_set_len(str, buf_len);
 
diff --git a/ext/openssl/ossl_x509attr.c b/ext/openssl/ossl_x509attr.c
index 0c0425c..86908d2 100644
--- a/ext/openssl/ossl_x509attr.c
+++ b/ext/openssl/ossl_x509attr.c
@@ -186,33 +186,38 @@ static VALUE
 ossl_x509attr_set_value(VALUE self, VALUE value)
 {
     X509_ATTRIBUTE *attr;
-    ASN1_TYPE *a1type;
+    VALUE asn1_value;
+    int i, asn1_tag;
+
+    OSSL_Check_Kind(value, cASN1Data);
+    asn1_value = rb_attr_get(value, rb_intern("@value"));
+    asn1_tag = NUM2INT(rb_attr_get(value, rb_intern("@tag")));
+    if (asn1_tag != V_ASN1_SET)
+	ossl_raise(eASN1Error, "argument must be a SET");
+    if (!rb_obj_is_kind_of(asn1_value, rb_cArray))
+	ossl_raise(eASN1Error, "ASN1::Set has non-array value (bug)");
 
-    if(!(a1type = ossl_asn1_get_asn1type(value)))
-	ossl_raise(eASN1Error, "could not get ASN1_TYPE");
-    if(ASN1_TYPE_get(a1type) == V_ASN1_SEQUENCE){
-	ASN1_TYPE_free(a1type);
-	ossl_raise(eASN1Error, "couldn't set SEQUENCE for attribute value.");
-    }
     GetX509Attr(self, attr);
     if (X509_ATTRIBUTE_count(attr)) {
 	/* populated, reset first */
 	ASN1_OBJECT *obj = X509_ATTRIBUTE_get0_object(attr);
 	X509_ATTRIBUTE *new_attr = X509_ATTRIBUTE_new();
-	if (!new_attr) {
-	    ASN1_TYPE_free(a1type);
+	if (!new_attr)
 	    ossl_raise(eX509AttrError, NULL);
-	}
 	SetX509Attr(self, new_attr);
 	X509_ATTRIBUTE_set1_object(new_attr, obj);
 	X509_ATTRIBUTE_free(attr);
 	attr = new_attr;
     }
-    if (!X509_ATTRIBUTE_set1_data(attr, ASN1_TYPE_get(a1type), a1type->value.ptr, -1)) {
+
+    for (i = 0; i < RARRAY_LEN(asn1_value); i++) {
+	int ret;
+	ASN1_TYPE *a1type = ossl_asn1_get_asn1type(RARRAY_AREF(asn1_value, i));
+	ret = X509_ATTRIBUTE_set1_data(attr, ASN1_TYPE_get(a1type), a1type->value.ptr, -1);
 	ASN1_TYPE_free(a1type);
-	ossl_raise(eX509AttrError, NULL);
+	if (!ret)
+	    ossl_raise(eX509AttrError, NULL);
     }
-    ASN1_TYPE_free(a1type);
 
     return value;
 }
@@ -226,46 +231,27 @@ ossl_x509attr_get_value(VALUE self)
 {
     X509_ATTRIBUTE *attr;
     VALUE str;
-    long length;
     unsigned char *p;
-    int count;
+    STACK_OF(ASN1_TYPE) *sk;
+    int i, count;
+
+    /* there is no X509_ATTRIBUTE_get0_set() function.. */
+    sk = sk_ASN1_TYPE_new_null();
+    if (!sk)
+	ossl_raise(eX509AttrError, "sk_new() failed");
 
     GetX509Attr(self, attr);
     count = X509_ATTRIBUTE_count(attr);
-    if (!count) return Qnil;
-    if (count == 1) {
-	ASN1_TYPE *a1type = X509_ATTRIBUTE_get0_type(attr, 0);
-	length = i2d_ASN1_TYPE(a1type, NULL);
-	str = rb_str_new(0, length);
-	p = (unsigned char *)RSTRING_PTR(str);
-	i2d_ASN1_TYPE(a1type, &p);
-    }
-    else {
-#if defined(i2d_ASN1_SET_OF_ASN1_TYPE)
-	length = i2d_ASN1_SET_OF_ASN1_TYPE(attr->value.set,
-		(unsigned char **)NULL, i2d_ASN1_TYPE,
-		V_ASN1_SET, V_ASN1_UNIVERSAL, 0);
-	str = rb_str_new(0, length);
-	p = (unsigned char *)RSTRING_PTR(str);
-	i2d_ASN1_SET_OF_ASN1_TYPE(attr->value.set,
-		&p, i2d_ASN1_TYPE,
-		V_ASN1_SET, V_ASN1_UNIVERSAL, 0);
-#else
-	STACK_OF(ASN1_TYPE) *sk = sk_ASN1_TYPE_new_null();
-	int i;
-
-	if (!sk) ossl_raise(eX509AttrError, "sk_new() failed");
-	for (i = 0; i < count; i++)
-	    sk_ASN1_TYPE_push(sk, X509_ATTRIBUTE_get0_type(attr, i));
-	length = i2d_ASN1_SET_ANY(sk, NULL);
-	str = rb_str_new(0, length);
-	p = (unsigned char *)RSTRING_PTR(str);
-	i2d_ASN1_SET_ANY(sk, &p);
-	sk_ASN1_TYPE_free(sk);
-#endif
-    }
+    for (i = 0; i < count; i++)
+	sk_ASN1_TYPE_push(sk, X509_ATTRIBUTE_get0_type(attr, i));
+
+    str = rb_str_new(0, i2d_ASN1_SET_ANY(sk, NULL));
+    p = (unsigned char *)RSTRING_PTR(str);
+    i2d_ASN1_SET_ANY(sk, &p);
     ossl_str_adjust(str, p);
 
+    sk_ASN1_TYPE_free(sk);
+
     return rb_funcall(mASN1, rb_intern("decode"), 1, str);
 }
 
@@ -288,7 +274,7 @@ ossl_x509attr_to_der(VALUE self)
     p = (unsigned char *)RSTRING_PTR(str);
     if(i2d_X509_ATTRIBUTE(attr, &p) <= 0)
 	ossl_raise(eX509AttrError, NULL);
-    rb_str_set_len(str, p - (unsigned char*)RSTRING_PTR(str));
+    ossl_str_adjust(str, p);
 
     return str;
 }
diff --git a/test/openssl/test_x509attr.rb b/test/openssl/test_x509attr.rb
new file mode 100644
index 0000000..c088503
--- /dev/null
+++ b/test/openssl/test_x509attr.rb
@@ -0,0 +1,47 @@
+# frozen_string_literal: false
+require_relative "utils"
+
+if defined?(OpenSSL::TestUtils)
+
+class OpenSSL::TestX509Attribute < Test::Unit::TestCase
+  def test_new
+    ef = OpenSSL::X509::ExtensionFactory.new
+    val = OpenSSL::ASN1::Set.new([OpenSSL::ASN1::Sequence.new([
+      ef.create_extension("keyUsage", "keyCertSign", true)
+    ])])
+    attr = OpenSSL::X509::Attribute.new("extReq", val)
+    assert_equal("extReq", attr.oid)
+    assert_equal(val.to_der, attr.value.to_der)
+  end
+
+  def test_from_der
+    # oid: challengePassword, values: Set[UTF8String<"abc123">]
+    test_der = "\x30\x15\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x09\x07\x31\x08" \
+      "\x0c\x06\x61\x62\x63\x31\x32\x33".b
+    attr = OpenSSL::X509::Attribute.new(test_der)
+    assert_equal(test_der, attr.to_der)
+    assert_equal("challengePassword", attr.oid)
+    assert_equal("abc123", attr.value.value[0].value)
+  end
+
+  def test_to_der
+    ef = OpenSSL::X509::ExtensionFactory.new
+    val = OpenSSL::ASN1::Set.new([OpenSSL::ASN1::Sequence.new([
+      ef.create_extension("keyUsage", "keyCertSign", true)
+    ])])
+    attr = OpenSSL::X509::Attribute.new("extReq", val)
+    expected = OpenSSL::ASN1::Sequence.new([
+      OpenSSL::ASN1::ObjectId.new("extReq"),
+      val
+    ])
+    assert_equal(expected.to_der, attr.to_der)
+  end
+
+  def test_invalid_value
+    assert_raise(TypeError) {
+      OpenSSL::X509::Attribute.new("challengePassword", "1234")
+    }
+  end
+end
+
+end
