From d2868c4f77b1c2be2839bdf0a18fa6b2708f99de Mon Sep 17 00:00:00 2001 From: Ivy Huang Date: Sun, 19 Oct 2025 06:49:28 -0400 Subject: [PATCH 1/6] refactor: move definition of EvpPKey up this is in preparation for adding signature support in the digests section --- src/OpenSSL.jl | 376 ++++++++++++++++++++++++------------------------- 1 file changed, 188 insertions(+), 188 deletions(-) diff --git a/src/OpenSSL.jl b/src/OpenSSL.jl index e1dcb40..aa6ec3a 100644 --- a/src/OpenSSL.jl +++ b/src/OpenSSL.jl @@ -1162,132 +1162,6 @@ function Base.getproperty(evp_cipher_ctx::EvpCipherContext, name::Symbol) end end -""" - EVP Message Digest. -""" -mutable struct EvpDigest - evp_md::Ptr{Cvoid} -end - -EvpMDNull()::EvpDigest = EvpDigest(ccall((:EVP_md_null, libcrypto), Ptr{Cvoid}, ())) - -EvpMD2()::EvpDigest = EvpDigest(ccall((:EVP_md2, libcrypto), Ptr{Cvoid}, ())) - -EvpMD5()::EvpDigest = EvpDigest(ccall((:EVP_md5, libcrypto), Ptr{Cvoid}, ())) - -EvpSHA1()::EvpDigest = EvpDigest(ccall((:EVP_sha1, libcrypto), Ptr{Cvoid}, ())) - -EvpSHA224()::EvpDigest = EvpDigest(ccall((:EVP_sha224, libcrypto), Ptr{Cvoid}, ())) - -EvpSHA256()::EvpDigest = EvpDigest(ccall((:EVP_sha256, libcrypto), Ptr{Cvoid}, ())) - -EvpSHA384()::EvpDigest = EvpDigest(ccall((:EVP_sha384, libcrypto), Ptr{Cvoid}, ())) - -EvpSHA512()::EvpDigest = EvpDigest(ccall((:EVP_sha512, libcrypto), Ptr{Cvoid}, ())) - -EvpDSS1()::EvpDigest = EvpDigest(ccall((:EVP_dss1, libcrypto), Ptr{Cvoid}, ())) - -""" - EVP Message Digest Context. -""" -mutable struct EvpDigestContext - evp_md_ctx::Ptr{Cvoid} - - function EvpDigestContext() - evp_digest_ctx = ccall( - (:EVP_MD_CTX_new, libcrypto), - Ptr{Cvoid}, - ()) - if evp_digest_ctx == C_NULL - throw(OpenSSLError()) - end - - evp_digest_ctx = new(evp_digest_ctx) - finalizer(free, evp_digest_ctx) - - return evp_digest_ctx - end -end - -function free(evp_digest_ctx::EvpDigestContext) - ccall( - (:EVP_MD_CTX_free, libcrypto), - Cvoid, - (EvpDigestContext,), - evp_digest_ctx) - - evp_digest_ctx.evp_md_ctx = C_NULL - return nothing -end - -function digest_init(evp_digest_ctx::EvpDigestContext, evp_digest::EvpDigest) - if ccall( - (:EVP_DigestInit_ex, libcrypto), - Cint, - (EvpDigestContext, EvpDigest, Ptr{Cvoid}), - evp_digest_ctx, - evp_digest, - C_NULL) != 1 - throw(OpenSSLError()) - end -end - -function digest_update(evp_digest_ctx::EvpDigestContext, in_data::Vector{UInt8}) - GC.@preserve in_data begin - if ccall( - (:EVP_DigestUpdate, libcrypto), - Cint, - (EvpDigestContext, Ptr{UInt8}, Csize_t), - evp_digest_ctx, - pointer(in_data), - length(in_data)) != 1 - throw(OpenSSLError()) - end - end -end - -function digest_final(evp_digest_ctx::EvpDigestContext)::Vector{UInt8} - out_data = Vector{UInt8}(undef, EVP_MAX_MD_SIZE) - out_length = Ref{UInt32}(0) - - GC.@preserve out_data out_length begin - if ccall( - (:EVP_DigestFinal_ex, libcrypto), - Cint, - (EvpDigestContext, Ptr{UInt8}, Ptr{UInt32}), - evp_digest_ctx, - pointer(out_data), - pointer_from_objref(out_length)) != 1 - throw(OpenSSLError()) - end - end - - resize!(out_data, out_length.x) - - return out_data -end - -""" - Computes the message digest (hash). -""" -function digest(evp_digest::EvpDigest, io::IO) - md_ctx = EvpDigestContext() - - digest_init(md_ctx, evp_digest) - - while !eof(io) - available_bytes = bytesavailable(io) - in_data = read(io, available_bytes) - digest_update(md_ctx, in_data) - end - - result = digest_final(md_ctx) - - finalize(md_ctx) - - return result -end - """ RSA structure. The RSA structure consists of several BIGNUM components. @@ -1690,68 +1564,6 @@ end Base.write(bio::BIO, out_data) = return unsafe_write(bio, pointer(out_data), length(out_data)) -""" - ASN1_TIME. -""" -mutable struct Asn1Time - asn1_time::Ptr{Cvoid} - - Asn1Time(asn1_time::Ptr{Cvoid}) = new(asn1_time) - - Asn1Time() = Asn1Time(0) - - Asn1Time(date_time::DateTime) = Asn1Time(Int64(floor(datetime2unix(date_time)))) - - function Asn1Time(unix_time::Int) - asn1_time = ccall( - (:ASN1_TIME_set, libcrypto), - Ptr{Cvoid}, - (Ptr{Cvoid}, Int64), - C_NULL, - unix_time) - if asn1_time == C_NULL - throw(OpenSSLError()) - end - - asn1_time = new(asn1_time) - finalizer(free, asn1_time) - - return asn1_time - end -end - -function free(asn1_time::Asn1Time) - ccall( - (:ASN1_STRING_free, libcrypto), - Cvoid, - (Asn1Time,), - asn1_time) - - asn1_time.asn1_time = C_NULL - return nothing -end - -function Dates.adjust(asn1_time::Asn1Time, seconds::Second) - adj_asn1_time = ccall( - (:X509_gmtime_adj, libcrypto), - Ptr{Cvoid}, - (Asn1Time, Int64), - asn1_time, - seconds.value) - if adj_asn1_time == C_NULL - throw(OpenSSLError()) - end - - if (adj_asn1_time != asn1_time.asn1_time) - free(asn1_time) - asn1_time.asn1_time = adj_asn1_time - end -end - -Dates.adjust(asn1_time::Asn1Time, days::Day) = Dates.adjust(asn1_time, Second(days)) - -Dates.adjust(asn1_time::Asn1Time, years::Year) = Dates.adjust(asn1_time, Day(365 * years.value)) - """ EVP_PKEY, EVP Public Key interface. """ @@ -1900,6 +1712,194 @@ function Base.getproperty(evp_pkey::EvpPKey, name::Symbol) end end +""" + EVP Message Digest. +""" +mutable struct EvpDigest + evp_md::Ptr{Cvoid} +end + +EvpMDNull()::EvpDigest = EvpDigest(ccall((:EVP_md_null, libcrypto), Ptr{Cvoid}, ())) + +EvpMD2()::EvpDigest = EvpDigest(ccall((:EVP_md2, libcrypto), Ptr{Cvoid}, ())) + +EvpMD5()::EvpDigest = EvpDigest(ccall((:EVP_md5, libcrypto), Ptr{Cvoid}, ())) + +EvpSHA1()::EvpDigest = EvpDigest(ccall((:EVP_sha1, libcrypto), Ptr{Cvoid}, ())) + +EvpSHA224()::EvpDigest = EvpDigest(ccall((:EVP_sha224, libcrypto), Ptr{Cvoid}, ())) + +EvpSHA256()::EvpDigest = EvpDigest(ccall((:EVP_sha256, libcrypto), Ptr{Cvoid}, ())) + +EvpSHA384()::EvpDigest = EvpDigest(ccall((:EVP_sha384, libcrypto), Ptr{Cvoid}, ())) + +EvpSHA512()::EvpDigest = EvpDigest(ccall((:EVP_sha512, libcrypto), Ptr{Cvoid}, ())) + +EvpDSS1()::EvpDigest = EvpDigest(ccall((:EVP_dss1, libcrypto), Ptr{Cvoid}, ())) + +""" + EVP Message Digest Context. +""" +mutable struct EvpDigestContext + evp_md_ctx::Ptr{Cvoid} + + function EvpDigestContext() + evp_digest_ctx = ccall( + (:EVP_MD_CTX_new, libcrypto), + Ptr{Cvoid}, + ()) + if evp_digest_ctx == C_NULL + throw(OpenSSLError()) + end + + evp_digest_ctx = new(evp_digest_ctx) + finalizer(free, evp_digest_ctx) + + return evp_digest_ctx + end +end + +function free(evp_digest_ctx::EvpDigestContext) + ccall( + (:EVP_MD_CTX_free, libcrypto), + Cvoid, + (EvpDigestContext,), + evp_digest_ctx) + + evp_digest_ctx.evp_md_ctx = C_NULL + return nothing +end + +function digest_init(evp_digest_ctx::EvpDigestContext, evp_digest::EvpDigest) + if ccall( + (:EVP_DigestInit_ex, libcrypto), + Cint, + (EvpDigestContext, EvpDigest, Ptr{Cvoid}), + evp_digest_ctx, + evp_digest, + C_NULL) != 1 + throw(OpenSSLError()) + end +end + +function digest_update(evp_digest_ctx::EvpDigestContext, in_data::Vector{UInt8}) + GC.@preserve in_data begin + if ccall( + (:EVP_DigestUpdate, libcrypto), + Cint, + (EvpDigestContext, Ptr{UInt8}, Csize_t), + evp_digest_ctx, + pointer(in_data), + length(in_data)) != 1 + throw(OpenSSLError()) + end + end +end + +function digest_final(evp_digest_ctx::EvpDigestContext)::Vector{UInt8} + out_data = Vector{UInt8}(undef, EVP_MAX_MD_SIZE) + out_length = Ref{UInt32}(0) + + GC.@preserve out_data out_length begin + if ccall( + (:EVP_DigestFinal_ex, libcrypto), + Cint, + (EvpDigestContext, Ptr{UInt8}, Ptr{UInt32}), + evp_digest_ctx, + pointer(out_data), + pointer_from_objref(out_length)) != 1 + throw(OpenSSLError()) + end + end + + resize!(out_data, out_length.x) + + return out_data +end + +""" + Computes the message digest (hash). +""" +function digest(evp_digest::EvpDigest, io::IO) + md_ctx = EvpDigestContext() + + digest_init(md_ctx, evp_digest) + + while !eof(io) + available_bytes = bytesavailable(io) + in_data = read(io, available_bytes) + digest_update(md_ctx, in_data) + end + + result = digest_final(md_ctx) + + finalize(md_ctx) + + return result +end + +""" + ASN1_TIME. +""" +mutable struct Asn1Time + asn1_time::Ptr{Cvoid} + + Asn1Time(asn1_time::Ptr{Cvoid}) = new(asn1_time) + + Asn1Time() = Asn1Time(0) + + Asn1Time(date_time::DateTime) = Asn1Time(Int64(floor(datetime2unix(date_time)))) + + function Asn1Time(unix_time::Int) + asn1_time = ccall( + (:ASN1_TIME_set, libcrypto), + Ptr{Cvoid}, + (Ptr{Cvoid}, Int64), + C_NULL, + unix_time) + if asn1_time == C_NULL + throw(OpenSSLError()) + end + + asn1_time = new(asn1_time) + finalizer(free, asn1_time) + + return asn1_time + end +end + +function free(asn1_time::Asn1Time) + ccall( + (:ASN1_STRING_free, libcrypto), + Cvoid, + (Asn1Time,), + asn1_time) + + asn1_time.asn1_time = C_NULL + return nothing +end + +function Dates.adjust(asn1_time::Asn1Time, seconds::Second) + adj_asn1_time = ccall( + (:X509_gmtime_adj, libcrypto), + Ptr{Cvoid}, + (Asn1Time, Int64), + asn1_time, + seconds.value) + if adj_asn1_time == C_NULL + throw(OpenSSLError()) + end + + if (adj_asn1_time != asn1_time.asn1_time) + free(asn1_time) + asn1_time.asn1_time = adj_asn1_time + end +end + +Dates.adjust(asn1_time::Asn1Time, days::Day) = Dates.adjust(asn1_time, Second(days)) + +Dates.adjust(asn1_time::Asn1Time, years::Year) = Dates.adjust(asn1_time, Day(365 * years.value)) + """ Stack Of. """ From 4c251f819bd7e6108ba18f5255b352968930e8a1 Mon Sep 17 00:00:00 2001 From: Ivy Huang Date: Sun, 19 Oct 2025 22:04:49 -0400 Subject: [PATCH 2/6] feat: add digestsign functions but doesn't seem to be working properly yet ... --- src/OpenSSL.jl | 84 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 82 insertions(+), 2 deletions(-) diff --git a/src/OpenSSL.jl b/src/OpenSSL.jl index aa6ec3a..468507a 100644 --- a/src/OpenSSL.jl +++ b/src/OpenSSL.jl @@ -28,8 +28,10 @@ export TLSv12ClientMethod, TLSv12ServerMethod, X509Request, X509Store, X509Attribute, X509Extension, P12Object, EvpDigestContext, EvpCipherContext, EvpEncNull, EvpBlowFishCBC, EvpBlowFishECB, EvpBlowFishCFB, EvpBlowFishOFB, EvpAES128CBC, EvpAES128ECB, EvpAES128CFB, EvpAES128OFB, EvpMDNull, EvpMD2, EvpMD5, EvpSHA1, EvpDSS1, - encrypt_init, cipher, add_extension, add_extensions, decrypt_init, digest_init, digest_update, digest_final, - digest, random_bytes, rsa_generate_key, dsa_generate_key, add_entry, sign_certificate, sign_request, adjust, + encrypt_init, cipher, add_extension, add_extensions, decrypt_init, + digest_init, digest_update, digest_final, digest, + digestsign_init, digestsign_update, digestsign_final, digestsign, + random_bytes, rsa_generate_key, dsa_generate_key, add_entry, sign_certificate, sign_request, adjust, add_cert, unpack, eof, isreadable, iswritable, bytesavailable, read, unsafe_write, connect, get_peer_certificate, free, HTTP2_ALPN, UPDATE_HTTP2_ALPN, version @@ -1838,6 +1840,84 @@ function digest(evp_digest::EvpDigest, io::IO) return result end +function digestsign_init( + evp_digest_ctx::EvpDigestContext, + evp_digest::EvpDigest, + pkey::EvpPKey, +) + if ccall( + (:EVP_DigestSignInit, libcrypto), + Cint, + (EvpDigestContext, Ptr{Ptr{Cvoid}}, EvpDigest, Ptr{Cvoid}, EvpPKey), + evp_digest_ctx, + C_NULL, + evp_digest, + C_NULL, + pkey) != 1 + throw(OpenSSLError()) + end +end + +function digestsign_update(evp_digest_ctx::EvpDigestContext, in_data::Vector{UInt8}) + GC.@preserve in_data begin + if ccall( + (:EVP_DigestSignUpdate, libcrypto), + Cint, + (EvpDigestContext, Ptr{UInt8}, Csize_t), + evp_digest_ctx, + pointer(in_data), + length(in_data)) != 1 + throw(OpenSSLError()) + end + end +end + +function digestsign_final(evp_digest_ctx::EvpDigestContext)::Vector{UInt8} + out_data = Vector{UInt8}(undef, EVP_MAX_MD_SIZE) + out_length = Ref{UInt32}(0) + + GC.@preserve out_data out_length begin + if ccall( + (:EVP_DigestSignFinal, libcrypto), + Cint, + (EvpDigestContext, Ptr{UInt8}, Ptr{UInt32}), + evp_digest_ctx, + pointer(out_data), + pointer_from_objref(out_length)) != 1 + throw(OpenSSLError()) + end + end + + resize!(out_data, out_length.x) + + return out_data +end + +""" + Computes the message signature. + + Note that unlike OpenSSL's EVP_DigestSign, this is equivalent to calling all + three of digestsign_init, digest_update, and digest_final, not just + the latter two. +""" +function digestsign(evp_digest::EvpDigest, io::IO, pkey::EvpPKey) + md_ctx = EvpDigestContext() + + digestsign_init(md_ctx, evp_digest, pkey) + + while !eof(io) + available_bytes = bytesavailable(io) + in_data = read(io, available_bytes) + digest_update(md_ctx, in_data) + end + + result = digest_final(md_ctx) + + finalize(md_ctx) + + return result +end + """ ASN1_TIME. """ From bfcabd8e6b2212c1f5db01b0154a362abbb397b7 Mon Sep 17 00:00:00 2001 From: Ivy Huang Date: Fri, 24 Oct 2025 22:29:35 -0400 Subject: [PATCH 3/6] fix(digestsign_final): properly set buffer length --- src/OpenSSL.jl | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/OpenSSL.jl b/src/OpenSSL.jl index 468507a..42f47c1 100644 --- a/src/OpenSSL.jl +++ b/src/OpenSSL.jl @@ -1873,23 +1873,35 @@ function digestsign_update(evp_digest_ctx::EvpDigestContext, in_data::Vector{UIn end function digestsign_final(evp_digest_ctx::EvpDigestContext)::Vector{UInt8} - out_data = Vector{UInt8}(undef, EVP_MAX_MD_SIZE) - out_length = Ref{UInt32}(0) + out_length = Ref{Csize_t}(0) + # first pass to get out_length + GC.@preserve out_length begin + if ccall( + (:EVP_DigestSignFinal, libcrypto), + Cint, + (EvpDigestContext, Ptr{UInt8}, Ptr{Csize_t}), + evp_digest_ctx, + C_NULL, + out_length) != 1 + throw(OpenSSLError()) + end + end + + out_data = Vector{UInt8}(undef, out_length.x) + # second pass to actually sign GC.@preserve out_data out_length begin if ccall( (:EVP_DigestSignFinal, libcrypto), Cint, - (EvpDigestContext, Ptr{UInt8}, Ptr{UInt32}), + (EvpDigestContext, Ptr{UInt8}, Ptr{Csize_t}), evp_digest_ctx, pointer(out_data), - pointer_from_objref(out_length)) != 1 + out_length) != 1 throw(OpenSSLError()) end end - resize!(out_data, out_length.x) - return out_data end From 26c5bbc9b43e1e1629c896b63d750174809c0e06 Mon Sep 17 00:00:00 2001 From: Ivy Huang Date: Fri, 24 Oct 2025 22:32:06 -0400 Subject: [PATCH 4/6] fix(digestsign): call correct variants, oops --- src/OpenSSL.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/OpenSSL.jl b/src/OpenSSL.jl index 42f47c1..3367a72 100644 --- a/src/OpenSSL.jl +++ b/src/OpenSSL.jl @@ -27,7 +27,7 @@ export TLSv12ClientMethod, TLSv12ServerMethod, SSLStream, BigNum, EvpPKey, RSA, DSA, Asn1Time, X509Name, StackOf, X509Certificate, X509Request, X509Store, X509Attribute, X509Extension, P12Object, EvpDigestContext, EvpCipherContext, EvpEncNull, EvpBlowFishCBC, EvpBlowFishECB, EvpBlowFishCFB, EvpBlowFishOFB, EvpAES128CBC, - EvpAES128ECB, EvpAES128CFB, EvpAES128OFB, EvpMDNull, EvpMD2, EvpMD5, EvpSHA1, EvpDSS1, + EvpAES128ECB, EvpAES128CFB, EvpAES128OFB, EvpMDNull, EvpMD2, EvpMD5, EvpSHA1, EvpSHA256, EvpDSS1, encrypt_init, cipher, add_extension, add_extensions, decrypt_init, digest_init, digest_update, digest_final, digest, digestsign_init, digestsign_update, digestsign_final, digestsign, @@ -1920,10 +1920,10 @@ function digestsign(evp_digest::EvpDigest, io::IO, pkey::EvpPKey) while !eof(io) available_bytes = bytesavailable(io) in_data = read(io, available_bytes) - digest_update(md_ctx, in_data) + digestsign_update(md_ctx, in_data) end - result = digest_final(md_ctx) + result = digestsign_final(md_ctx) finalize(md_ctx) From 2ae60b3912bb8b66094edcee69110680c6aa312d Mon Sep 17 00:00:00 2001 From: Ivy Huang Date: Sat, 25 Oct 2025 00:13:24 -0400 Subject: [PATCH 5/6] refactor: clean up exports - exports now listed in file order and grouped by relevance - removed undefined exports (TLSv12ClientMethod, TLSv12ServerMethod, read) - removed EvpMD2 and EvpDSS1 which don't correspond to openssl symbols - closes #28 --- src/OpenSSL.jl | 46 +++++++++++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/src/OpenSSL.jl b/src/OpenSSL.jl index 3367a72..b45608a 100644 --- a/src/OpenSSL.jl +++ b/src/OpenSSL.jl @@ -23,17 +23,37 @@ Error handling: we clear the OpenSSL error queue, and store the error messages in Julia task TLS. """ -export TLSv12ClientMethod, TLSv12ServerMethod, - SSLStream, BigNum, EvpPKey, RSA, DSA, Asn1Time, X509Name, StackOf, X509Certificate, - X509Request, X509Store, X509Attribute, X509Extension, P12Object, EvpDigestContext, EvpCipherContext, - EvpEncNull, EvpBlowFishCBC, EvpBlowFishECB, EvpBlowFishCFB, EvpBlowFishOFB, EvpAES128CBC, - EvpAES128ECB, EvpAES128CFB, EvpAES128OFB, EvpMDNull, EvpMD2, EvpMD5, EvpSHA1, EvpSHA256, EvpDSS1, - encrypt_init, cipher, add_extension, add_extensions, decrypt_init, - digest_init, digest_update, digest_final, digest, - digestsign_init, digestsign_update, digestsign_final, digestsign, - random_bytes, rsa_generate_key, dsa_generate_key, add_entry, sign_certificate, sign_request, adjust, - add_cert, unpack, eof, isreadable, iswritable, bytesavailable, read, unsafe_write, connect, - get_peer_certificate, free, HTTP2_ALPN, UPDATE_HTTP2_ALPN, version +export HTTP2_ALPN, UPDATE_HTTP2_ALPN +export version +export random_bytes +export BigNum +export free +export EvpBlowFishCBC, EvpBlowFishECB, EvpBlowFishCFB, EvpBlowFishOFB +export EvpAES128CBC, EvpAES128ECB, EvpAES128CFB, EvpAES128OFB +export EvpEncNull +export EvpCipherContext +export decrypt_init, encrypt_init, cipher +export RSA, rsa_generate_key +export DSA, dsa_generate_key +export EvpPKey +export EvpMDNull, EvpMD5, EvpSHA1, EvpSHA224, EvpSHA256, EvpSHA384, EvpSHA512 +export EvpDigestContext +export digest_init, digest_update, digest_final, digest +export digestsign_init, digestsign_update, digestsign_final, digestsign +export Asn1Time, adjust +export StackOf +export X509Name, add_entry +export X509Attribute +export X509Extension +export X509Certificate, sign_certificate, add_extension +export X509Request, add_extensions, sign_request +export X509Store, add_cert +export P12Object, unpack + +# from ssl.jl +export SSLStream +export isreadable, iswritable, eof, bytesavailable, unsafe_write +export connect, get_peer_certificate const Option{T} = Union{Nothing,T} where {T} @@ -1723,8 +1743,6 @@ end EvpMDNull()::EvpDigest = EvpDigest(ccall((:EVP_md_null, libcrypto), Ptr{Cvoid}, ())) -EvpMD2()::EvpDigest = EvpDigest(ccall((:EVP_md2, libcrypto), Ptr{Cvoid}, ())) - EvpMD5()::EvpDigest = EvpDigest(ccall((:EVP_md5, libcrypto), Ptr{Cvoid}, ())) EvpSHA1()::EvpDigest = EvpDigest(ccall((:EVP_sha1, libcrypto), Ptr{Cvoid}, ())) @@ -1737,8 +1755,6 @@ EvpSHA384()::EvpDigest = EvpDigest(ccall((:EVP_sha384, libcrypto), Ptr{Cvoid}, ( EvpSHA512()::EvpDigest = EvpDigest(ccall((:EVP_sha512, libcrypto), Ptr{Cvoid}, ())) -EvpDSS1()::EvpDigest = EvpDigest(ccall((:EVP_dss1, libcrypto), Ptr{Cvoid}, ())) - """ EVP Message Digest Context. """ From 3db1e490bbe6659edf9648d39b17db4345056e2f Mon Sep 17 00:00:00 2001 From: Ivy Huang Date: Sun, 26 Oct 2025 01:03:24 -0400 Subject: [PATCH 6/6] test: rename Hash->Digest and test RSA DigestSign --- test/rsa_keypair.pem | 52 ++++++++++++++++++++++++++++++++++++++++++++ test/runtests.jl | 49 ++++++++++++++++++++++++++++++++++++++--- 2 files changed, 98 insertions(+), 3 deletions(-) create mode 100644 test/rsa_keypair.pem diff --git a/test/rsa_keypair.pem b/test/rsa_keypair.pem new file mode 100644 index 0000000..12095d6 --- /dev/null +++ b/test/rsa_keypair.pem @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +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 +4StaWaBmCrIZtIRAfGBj7TQU0vQ9f2g= +-----END PRIVATE KEY----- diff --git a/test/runtests.jl b/test/runtests.jl index 9ebabcf..3ee2502 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -269,9 +269,52 @@ end #finalize(ssl_ctx) end -@testset "Hash" begin - res = digest(EvpMD5(), IOBuffer("The quick brown fox jumps over the lazy dog")) - @test res == UInt8[0x9e, 0x10, 0x7d, 0x9d, 0x37, 0x2b, 0xb6, 0x82, 0x6b, 0xd8, 0x1d, 0x35, 0x42, 0xa4, 0x19, 0xd6] +@testset "Digest" begin + teststring = "The quick brown fox\n一二三" + @test digest(EvpMD5(), IOBuffer(teststring)) == UInt8[ + 0xb8, 0x8c, 0xf0, 0x30, 0x36, 0x62, 0xb8, 0x11, 0x5b, 0x80, 0x6f, 0xd3, + 0xab, 0xff, 0xdf, 0xb7 + ] + @test digest(EvpSHA1(), IOBuffer(teststring)) == UInt8[ + 0x90, 0xdb, 0x7f, 0xf8, 0x91, 0x5b, 0x0b, 0x19, 0x92, 0xee, 0xd6, 0x99, + 0xee, 0x73, 0x99, 0x67, 0xa2, 0x1e, 0xc6, 0xb3 + ] + @test digest(EvpSHA224(), IOBuffer(teststring)) == UInt8[ + 0x35, 0x9f, 0xba, 0x86, 0x72, 0xea, 0x68, 0xff, 0x61, 0x66, 0xe3, 0x80, + 0x79, 0xb4, 0xec, 0x50, 0x9b, 0x20, 0xe0, 0x93, 0xc1, 0xb0, 0xe5, 0x4e, + 0xca, 0x9c, 0xcc, 0x1b + ] + @test digest(EvpSHA256(), IOBuffer(teststring)) == UInt8[ + 0x30, 0x53, 0xc0, 0x66, 0xf0, 0xc7, 0x96, 0xa1, 0xa3, 0xa1, 0x3c, 0xb8, + 0x11, 0x05, 0xe2, 0x62, 0x25, 0x77, 0x07, 0xf5, 0xc3, 0xe1, 0x38, 0xb1, + 0xa0, 0x01, 0x5e, 0xd6, 0xfb, 0xa6, 0xe5, 0x0c + ] + @test digest(EvpSHA384(), IOBuffer(teststring)) == UInt8[ + 0xc2, 0xd6, 0x21, 0x4f, 0x31, 0x5e, 0x73, 0x6b, 0x03, 0xec, 0x3f, 0xac, + 0xd8, 0x7d, 0xa4, 0xeb, 0x28, 0xac, 0x04, 0x9d, 0xc8, 0x06, 0x9a, 0x58, + 0x6f, 0xe8, 0xa8, 0xa6, 0x35, 0x51, 0xbc, 0x21, 0x20, 0x9d, 0x37, 0x4f, + 0x87, 0xe7, 0x34, 0x59, 0x9c, 0x74, 0xd5, 0xc6, 0x4b, 0xf0, 0xd3, 0xf6 + ] + @test digest(EvpSHA512(), IOBuffer(teststring)) == UInt8[ + 0x65, 0xd4, 0xc1, 0x27, 0x65, 0x96, 0x3b, 0x6f, 0x8b, 0x91, 0x87, 0x3c, + 0x25, 0x62, 0xf7, 0x71, 0xc5, 0x68, 0x72, 0xae, 0x60, 0xaf, 0x89, 0x68, + 0x9a, 0x4e, 0xcf, 0x0b, 0xf7, 0x29, 0xde, 0x2a, 0x2d, 0xa3, 0xc9, 0x2d, + 0x2b, 0x59, 0xc2, 0xd1, 0xb1, 0xc9, 0x54, 0x7c, 0x07, 0xd7, 0x93, 0xc1, + 0xd4, 0x2b, 0x81, 0x7e, 0xd0, 0xf4, 0xee, 0xee, 0x8b, 0x84, 0x33, 0x6d, + 0x40, 0x0c, 0xfd, 0xe5 + ] +end + +@testset "DigestSign" begin + teststring = "The quick brown fox\n一二三" + open("rsa_keypair.pem") do f + rsa_key = EvpPKey(read(f, String)) + rsa_sig = digestsign(EvpSHA256(), IOBuffer(teststring), rsa_key) + @test digest(EvpMD5(), IOBuffer(rsa_sig)) == UInt8[ + 0x7d, 0xe9, 0x0c, 0x17, 0xed, 0xb4, 0x9c, 0xc1, 0xbc, 0xfc, 0x8a, + 0x3c, 0xba, 0x35, 0xdc, 0x45 + ] + end end @testset "SelfSignedCertificate" begin