How To Fix `do_sigver_init:no default digest` and Upgrading to AWS Signature Version 4 for S3 Uploads in Perl
erics, Posted July 28th, 2025 at 8:03:35am
When performing direct S3 file uploads using custom Perl scripts, I recently encountered the following cryptic error:
|
1 |
405C5D73C37F0000:error:0300009E:digital envelope routines:do_sigver_init:no default digest:crypto/evp/m_sigver.c:372: |
Alongside this, the AWS S3 server returned:
|
1 2 3 4 |
<Error> InvalidArgument <Message>AWS authorization header is invalid. Expected AwsAccessKeyId:signature</Message> </Error> |
This post explains:
* What causes the error
* Why it’s tied to deprecated AWS Signature Version 2 (SigV2)
* How to fully upgrade a Perl curl‑based S3 upload to Signature Version 4 (SigV4) using only core Perl modules
💥 The Problem
OpenSSL 3.0 Breaks Legacy HMAC Signatures
The OpenSSL error stems from a breaking change in OpenSSL 3.0+: digest algorithms (like **SHA‑1**) must now be explicitly declared when performing cryptographic operations. Legacy command‑line usage such as:
|
1 |
echo -n "string" | openssl sha1 -hmac SECRET -binary | base64 |
fails under OpenSSL 3+ with:
|
1 |
do_sigver_init:no default digest |
AWS Signature V2 Is Deprecated
The second error shows the deeper issue: the upload was signed using **Signature Version 2**, now deprecated and unsupported in most AWS regions.
SigV2 looks like:
|
1 |
Authorization: AWS <AccessKey>:<Base64Signature> |
AWS now requires **Signature Version 4**, which uses HMAC‑SHA256, a canonical request, and more secure metadata.
✅ The Solution: ✨ Rewrite the S3 Upload to Use Signature Version 4
Below is the refactored Perl subroutine uploadFile that uses SigV4 without relying on OpenSSL or any non‑core CPAN modules—just **Digest::SHA**, **MIME::Base64**, and **POSIX**.
🧩 Required Perl Modules
Add these at the top of your script:
|
1 2 3 |
use Digest::SHA qw(hmac_sha256 sha256_hex); use MIME::Base64 qw(encode_base64); use POSIX qw(strftime); |
🛠 Updated Signature Code (V4)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# region and credentials my $region = $g->{region} || 'us-east-1'; my $service = 's3'; my $algorithm = 'AWS4-HMAC-SHA256'; # timestamps my $amz_date = strftime('%Y%m%dT%H%M%SZ', gmtime); # e.g. 20250728T142500Z my $date_stamp = strftime('%Y%m%d', gmtime); # e.g. 20250728 # canonical scope my $canonical_uri = "/$datestamp/$objectName"; my $host = "$g->{bucket}.s3.amazonaws.com"; my $canonical_headers = "host:$host x-amz-content-sha256:UNSIGNED-PAYLOAD x-amz-date:$amz_date "; my $signed_headers = "host;x-amz-content-sha256;x-amz-date"; # canonical request my $canonical_request = join(" ", "PUT", $canonical_uri, "", $canonical_headers, $signed_headers, "UNSIGNED-PAYLOAD" ); my $hashed_canonical_request = sha256_hex($canonical_request); # string to sign my $credential_scope = "$date_stamp/$region/$service/aws4_request"; my $string_to_sign = join(" ", $algorithm, $amz_date, $credential_scope, $hashed_canonical_request ); # helper sub sign { hmac_sha256($_[1], $_[0]) } # derive signing key my $kSecret = "AWS4$g->{s3Secret}"; my $kDate = sign($kSecret, $date_stamp); my $kRegion = sign($kDate, $region); my $kService = sign($kRegion, $service); my $kSigning = sign($kService, "aws4_request"); # signature my $signature = unpack("H*", hmac_sha256($string_to_sign, $kSigning)); # authorization header my $authorization_header = "$algorithm Credential=$g->{s3Key}/$credential_scope, " . "SignedHeaders=$signed_headers, Signature=$signature"; |
📡 Updated curl Command
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
my @args = ( 'curl', '-sS', '-w', '%{http_code}', '-o', $tmpfile, '-X', 'PUT', '-T', $file, '-H', "Host: $host", '-H', "x-amz-date: $amz_date", '-H', "x-amz-content-sha256: UNSIGNED-PAYLOAD", '-H', "Authorization: $authorization_header", "https://$host/$datestamp/$objectName" ); |
*Using UNSIGNED-PAYLOAD skips hashing large files and is valid over HTTPS. If your bucket enforces payload signing, replace that value with the SHA‑256 of the file.*
🚀 Result
* No more **OpenSSL** errors.
* No more SigV2 deprecation warnings.
* Fully secure, modern, Perl‑only SigV4 uploads to Amazon S3 via curl.
🧠 Key Takeaways
| Aspect | Legacy (SigV2) | Modern (SigV4) |
|---|---|---|
| Crypto | HMAC‑SHA1 via openssl | HMAC‑SHA256 via Digest::SHA |
| Timestamp header | Date | x-amz-date |
| Auth header | AWS : | AWS4-HMAC-SHA256 … Signature=… |
| Perl dependencies | External openssl, base64 | Core modules only |
| Security / compliance | Deprecated | AWS‑recommended standard |
Categories: 
Leave Your Comment
All fields marked with "*" are required.