assign a grep value to a variable in pipe - bash

I have a pipe condition as:
if true | openssl s_client -connect $SSL_URL | openssl x509 -noout -dates -checkend 0 | grep 'notAfter';
now I want to take the value returned from grep 'notAfter' in a shell variable how can I do that.
I have tried this
if true | openssl s_client -connect $SSL_URL | openssl x509 -noout -dates -checkend 0 | A=$("grep 'notAfter'");
but it is not working.

You are probably looking for
if A=$(openssl s_client -connect "$SSL_URL" </dev/null |
openssl x509 -noout -dates -checkend 0 |
grep 'notAfter')
then
:
This assigns the output of the pipeline to the variable A, and checks the result code from grep; if it succeeded (i.e. a match was found) the then branch of the conditional is taken.
The pipe from true is odd and unconventional; I imagine the purpose of that was to make sure it doesn't receive anything useful on standard input. The usual way to do that is to redirect stdin to come from /dev/null so I'm doing that instead.
Finally, notice also the proper quoting of the variable. If SSL_URL would happen to contain a shell metacharacter, you would get an error or in the worst case a security problem.

Related

How to use OpenSSL to generate SHARSA1 base64 signature

I have generated a public/private keypair with OpenSSL. I want to use the private key now to sign my message using OpenSSL, and I was thinking to stay in a bash environment. I am required to use SHA-RSA1.
So far, I was suggested the following code but I am not happy with it:
openssl.exe dgst -sha1 -sign C:\...\path\to\key\privatekey.pem -binary C:\...\path\to\message\message.txt
I don't want to have my message be stored in a file (message.txt) to generate a signature and in any case, I would need to use openssl base64 afterwards to get the base64 representation.
Is there a more proper way to achieve what I want (and a one liner would be great)?
Use openssl itself to encode base64
echo "$msg" | openssl dgst ... -binary | openssl enc -base64

md5 hash function in binary format

I am trying to calculate the digests of a file using md5 algorithm. I am asked to format the output to be in binary not hex. So this is my command in terminal (I use mac):
openssl dgst -md5 -binary ~/Documents/msg_Joudi.txt > ~/Documents/hash.txt
this generates hash.txt file, but its content is not in binary format, and I do not know where is the error.
Create MD5 hash of file: msgFile.txt > Convert to Binary and save:
cat msgFile.txt | openssl dgst -md5 -binary > hash.bin.txt
Save binary in Base64 format:
cat msgFile.txt | openssl dgst -md5 -binary | base64 > hash.bin.b64.txt
Save binary in Hexadecimal representation:
cat msgFile.txt | openssl dgst -md5 -binary | xxd -b > hash.bin.hex.txt
The OP says he wants binary and then says "Binary should be 0s and 1s right?".
Although, probably unlikely, if he really wants a binary number output, do this:
$ echo -e "xx\nyy" >in.txt
$ perl -ln0777e 'use Digest::MD5 "md5"; print "0b".unpack("B*",md5($_))' <in.txt
0b001111000101011000010000100101100011010101000101111000101000000011110110011010110011010000!
Meaning of above:
slurp in whole file into $_, calculate md5 digest on $_ to create binary data
use unpack to convert binary data to binary number string
If he really wants binary data, modify the above:
$ perl -ln0777e 'use Digest::MD5 "md5"; print md5 $_' <in.txt >binout.txt

Accessing Azure blob storage using bash, curl

I am attempting to use the Azure blob storage service from a bash script using the REST API. I know it is possible to accomplish this using various other tools or languages, however I'd like to do it as a bash script.
The script below is an attempt to list the blobs in an Azure storage container.
This script results in an authentication error. The signing string and headers look correct based on the REST API (reference) documentation. I suspect the problem may be in juggling the various parts of the signing process.
Has anyone successfully used bash and curl to access cloud storage resources like Azure or other providers?
#!/bin/bash
# List the blobs in an Azure storage container.
echo "usage: ${0##*/} <storage-account-name> <container-name> <access-key>"
storage_account="$1"
container_name="$2"
access_key="$3"
blob_store_url="blob.core.windows.net"
authorization="SharedKey"
request_method="GET"
request_date=$(TZ=GMT date "+%a, %d %h %Y %H:%M:%S %Z")
storage_service_version="2011-08-18"
# HTTP Request headers
x_ms_date_h="x-ms-date:$request_date"
x_ms_version_h="x-ms-version:$storage_service_version"
# Build the signature string
canonicalized_headers="${x_ms_date_h}\n${x_ms_version_h}"
canonicalized_resource="/${storage_account}/${container_name}"
string_to_sign="${request_method}\n\n\n\n\n\n\n\n\n\n\n\n${canonicalized_headers}\n${canonicalized_resource}\ncomp:list\nrestype:container"
# Decode the Base64 encoded access key, convert to Hex.
decoded_hex_key="$(echo -n $access_key | base64 -d -w0 | xxd -p -c256)"
# Create the HMAC signature for the Authorization header
signature=$(echo -n "$string_to_sign" | openssl dgst -sha256 -mac HMAC -macopt "hexkey:$decoded_hex_key" | sed 's/^.*= //' | base64 -w0)
authorization_header="Authorization: $authorization $storage_account:$signature"
curl \
-H "$x_ms_date_h" \
-H "$x_ms_version_h" \
-H "$authorization_header" \
"https://${storage_account}.${blob_store_url}/${container_name}?restype=container&comp=list"
Update - The storage service error and the corresponding signing string that the script generated.
Following is what the storage service returns for the AuthenticationFailed error.
<?xml version="1.0" encoding="utf-8"?>
<Error>
<Code>AuthenticationFailed</Code>
<Message>Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.
RequestId:27e6337e-52f3-4e85-98c7-2fabaacd9ebc
Time:2013-11-21T22:10:11.7029042Z</Message>
<AuthenticationErrorDetail>The MAC signature found in the HTTP request
'OGYxYjk1MTFkYmNkMCgzN2YzODQwNzcyNiIyYTQxZDg0OWFjNGJiZDlmNWY5YzM1ZWQzMWViMGFjYTAyZDY4NAo='
is not the same as any computed signature. Server used following string to sign:
'GET
x-ms-date:Thu, 21 Nov 2013 22:10:11 GMT
x-ms-version:2011-08-18
/storage_account_name/storage_container
comp:list
restype:container'
</AuthenticationErrorDetail>
</Error>
Next is the string_to_sign that the script generates.
GET\n\n\n\n\n\n\n\n\n\n\n\nx-ms-date:Thu, 21 Nov 2013 22:10:11 GMT\nx-ms-version:2011-08-18\n/storage_account_name/storage_container\ncomp:list\nrestype:container
I was able to get it working.
There were two things wrong with this code, the first, as Patrick Park noted, was replacing the echo -n with printf. The second was replacing the sed magic with the -binary option on openssl.
Compare the original:
signature=$(echo -n "$string_to_sign" | openssl dgst -sha256 -mac HMAC -macopt "hexkey:$decoded_hex_key" -binary | sed 's/^.*= //' | base64 -w0)
with the fixed:
signature=$(printf "$string_to_sign" | openssl dgst -sha256 -mac HMAC -macopt "hexkey:$decoded_hex_key" -binary | base64 -w0)
The echo change is needed because echo -n will not convert the \n into actual newlines.
The -binary change is needed because even though you are stripping off the bad part, openssl was still outputting the signature in ascii-encoded-hex, not in binary. So after it was passed to base64, the result was the b64 encoded version of the hex representation, instead of the raw value.
Use Fiddler (or an equivalent on your platform) to intercept the call to Windows Azure Storage. On failure, this will show you the string that the Storage Service used to authenticate the call and you can compare this with the one you used.
Looking at the REST API documentation and your code above, I believe there's an issue with the way you're constructing canonicalized_resource string. You're missing the query parameters in that string. Your canonicalized_resource string should be:
canonicalized_resource="/${storage_account}/${container_name}\ncomp:list\nrestype:container"
It looks like openssl dgst does not generate proper HMAC for you.
I wrote a simple program in C that does the following:
Takes base64-encoded key from the command line and decodes it into binary.
Reads string to sign from standard input.
Uses libcrypto HMAC() routine to generate the signature.
base64-encodes the signature and prints the result to standard output.
I then replaced openssl dgst pipeline in your script with the call to my program and it did the trick.
Please note that the output you are getting from Azure is XML-wrapped and base-64 encoded, so you'll need to come up with some sort of parsing/conversion code for it.
use printf instead of echo (it works for me)
for example:
SIGNATURE=printf "$string_to_sign" | openssl dgst -sha256 -mac HMAC -macopt hexkey:$HEXKEY -binary | base64 -w0

Multiline Windows shell command with brackets and pipeline

I'm trying to encrypt some form data with OpenSSL on Windows and I'm having a hard time figuring out what's the correct syntax. With the following command, OpenSSL returns a PKCS7 message, but still gives me a & was unexpected at this time message.
(openssl smime -sign -signer client-public.pem -inkey client-private.pem -outform der -nodetach -binary^
formkey1=formvalue1^
formkey2=formvalue2^
formkey3=formvalue3^
^
^
) | openssl smime -encrypt -des3 -binary -outform pem server-public.pem
I feel like my pipeline is causing some problem in there but I have no idea what I should do to have a clean, error-free result.
There is no need to split it into multiple lines.
So you should first test if it works on a single line.
Then you could use the multiline caret, but don't forget to add a space in the next line, else it will paste the complete text together without any delimiters.
And the caret just before the closing parenthesis, will fail, as a multiline caret escapes the first character of the next line, so your closing parenthesis will not close anything.
This should work
(openssl smime -sign -signer client-public.pem -inkey client-private.pem -outform der -nodetach -binary^
formkey1=formvalue1^
formkey2=formvalue2^
formkey3=formvalue3^
^
^
) | openssl smime -encrypt -des3 -binary -outform pem server-public.pem

Encrypting using 64-bit DES with openssl

I'm trying to do a very simple thing, namely using a 64-bit password and a 64-bit plaintext (both in hex) and encrypt it with simple old DES.
my script looks like this:
plaintext=`echo -n "$2" | sed 's/\(..\)/\\\x\1/g'`
key=$1
printf "$plaintext" | openssl enc -nosalt -e -des -nopad -K "$key" -iv "0000000000000000" | od --format=x1 --width=32 --address-radix=n | sed 's/ //g'
I execute and get the following result:
./des_enc 5B5A57676A56676E 675A69675E5A6B5A
b617e2c84a4fba2149dd7132433031392257b99d9284b1031c351c15825aca52
The problem is there's too much data coming back from openssl, I expect to only get 64-bits of data instead I get 512. I don't know how to explicit request a 64-bit version of DES, is it even possible?
Note: The values used above are from "H. Katzan, The Standard Data Encryption Algorithm, pp75-94, Petrocelli Books Inc., New York, 1977" is:
Key: 5B5A57676A56676E
Plaintext: 675A69675E5A6B5A
Ciphertext: 974AFFBF86022D1F
Use -des-ecb. Also, xxd makes this pipeline much cleaner, if you have it handy (it's part of the vim package):
sh % echo 675A69675E5A6B5A | xxd -r -ps | openssl enc -des-ecb -nopad -K 5B5A57676A56676E | xxd -ps
974affbf86022d1f

Resources