将 Base64 CSR 提交给 Microsoft CA(通过 cURL)
Submitting Base64 CSR to a Microsoft CA (via cURL)
我已经编写了一个 bash 脚本来根据此 ServerFault link.
自动生成 IIS7 证书
我想通过 cURL 自动将代码签名请求 (CSR) 发送到内部 Microsoft 证书颁发机构 (MS CA),以下代码很有前途并已成功将 CSR 提交给 MS CA:
$ curl -k -u '<Domain>\<Username>':<Password> --ntlm
'https://<InternalMSCA>/certsrv/certfnsh.asp'
-H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'
-H 'Accept-Encoding: gzip, deflate' -H 'Accept-Language: en-US,en;q=0.5'
-H 'Connection: keep-alive'
-H 'Host: <InternalMSCA>'
-H 'Referer: https://<InternalMSCA>/certsrv/certrqxt.asp'
-H 'User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko'
-H 'Content-Type: application/x-www-form-urlencoded'
--data 'Mode=newreq&CertRequest=-----BEGIN+CERTIFICATE+REQUEST-----%0D%0AMIIDBjCCAe4CAQAwaDELMAkGA1UEBhMCQVUxDDAKBgNVBAgTA05TVzEPMA0GA1UE%0D%0ABxMGU3lkbmV5MQwwCgYDVQQKEwNZdW0xDjAMBgNVBAsTBVl1bUlTMRwwGgYDVQQD%0D%0AExN0ZXN0LmF1LmludC50Z3IubmV0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB%0D%0ACgKCAQEAygZvKhfs0mw4tModevTxOIz7eYYM%2B1axNv8FqoNyKr7xtqSbOMiNzf8R3rZ%0D%0A4cTcu5nv7oC7GHPMhnF7AdsO4XexwnKfnCkofECGkO6O4oTmRfUPLa38nV1%2BmytB%0D%0AlrQAl272jQdM9LSxTYW0OR9qO4mjAH1tvLF3IcC1OKOh6UNubdRFfE7dEXWnk%2BSF%0D%0AM8tgl0t3SFsRxrZL3vkgL%2B%2FEmvdOKXeoIey%2F7UMNeWRcwTkS1mw30HjvitJdQGZi%0D%0AgYJ6ldXrrITVKe9QXvVTxSl9NfzPHYp4yf%2FZvAJQmGLZ16aQo0PBeEfjkgkrcY5j%0D%0AMnVI2Q8yC%2BW9Bg%3D%3D%0D%0A-----END+CERTIFICATE+REQUEST-----&CertAttrib=CertificateTemplate%3A*WebServer%0D%0AUserAgent%3AMozilla%2F5.0+%28Windows+NT+6.3%3B+WOW64%3B+Trident%2F7.0%3B+rv%3A11.0%29+like+Gecko%0D%0A&FriendlyType=Saved-Request+Certificate+%287%2F7%2F2015%2C+3%3A46%3A39+PM%29&ThumbPrint=&TargetStoreFlags=0&SaveCert=yes'
| firefox "data:text/html;base64,$(base64 -w 0 <&0)"
我有兴趣在修改后重播此请求:
- 解码--数据(确定)
- 修改--数据(确定)
- 重新编码...(不正确)
编码:
Mode=newreq&CertRequest=-----BEGIN+CERTIFICATE+REQUEST-----%0D%0AMIIDBjCCAe4CAQAwaDELMAkGA1UEBhMCQVUxDDAKBgNVBAgTA05TVzEPMA0GA1UE%0D%0ABxMGU3lkbmV5MQwwCgYDVQQKEwNZdW0xDjAMBgNVBAsTBVl1bUlTMRwwGgYDVQQD%0D%0AExN0ZXN0LmF1LmludC50Z3IubmV0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB%0D%0ACgKCAQEAygZvKhfs0mw4tModevTxOIz7eYYM%2B1axNv8FqoNyKr7xtqSbOMiNzf8R3rZ%0D%0A4cTcu5nv7oC7GHPMhnF7AdsO4XexwnKfnCkofECGkO6O4oTmRfUPLa38nV1%2BmytB%0D%0AlrQAl272jQdM9LSxTYW0OR9qO4mjAH1tvLF3IcC1OKOh6UNubdRFfE7dEXWnk%2BSF%0D%0AM8tgl0t3SFsRxrZL3vkgL%2B%2FEmvdOKXeoIey%2F7UMNeWRcwTkS1mw30HjvitJdQGZi%0D%0AgYJ6ldXrrITVKe9QXvVTxSl9NfzPHYp4yf%2FZvAJQmGLZ16aQo0PBeEfjkgkrcY5j%0D%0AMnVI2Q8yC%2BW9Bg%3D%3D%0D%0A-----END+CERTIFICATE+REQUEST-----&CertAttrib=CertificateTemplate%3A*WebServer%0D%0AUserAgent%3AMozilla%2F5.0+%28Windows+NT+6.3%3B+WOW64%3B+Trident%2F7.0%3B+rv%3A11.0%29+like+Gecko%0D%0A&FriendlyType=Saved-Request+Certificate+%287%2F7%2F2015%2C+3%3A46%3A39+PM%29&ThumbPrint=&TargetStoreFlags=0&SaveCert=yes
解码:
Mode=newreq&CertRequest=-----BEGIN CERTIFICATE REQUEST-----
MIIDBjCCAe4CAQAwaDELMAkGA1UEBhMCQVUxDDAKBgNVBAgTA05TVzEPMA0GA1UE
BxMGU3lkbmV5MQwwCgYDVQQKEwNZdW0xDjAMBgNVBAsTBVl1bUlTMRwwGgYDVQQD
ExN0ZXN0LmF1LmludC50Z3IubmV0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
CgKCAQEAygZvKhfs0mw4tModevTxOIz7eYYM+1axNv8FqoNyKr7xtqSbOMiNzf8R3rZ
4cTcu5nv7oC7GHPMhnF7AdsO4XexwnKfnCkofECGkO6O4oTmRfUPLa38nV1+mytB
lrQAl272jQdM9LSxTYW0OR9qO4mjAH1tvLF3IcC1OKOh6UNubdRFfE7dEXWnk+SF
M8tgl0t3SFsRxrZL3vkgL+/EmvdOKXeoIey/7UMNeWRcwTkS1mw30HjvitJdQGZi
gYJ6ldXrrITVKe9QXvVTxSl9NfzPHYp4yf/ZvAJQmGLZ16aQo0PBeEfjkgkrcY5j
MnVI2Q8yC+W9Bg==
-----END CERTIFICATE REQUEST-----&CertAttrib=CertificateTemplate:*WebServer
UserAgent:Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0)
like Gecko &FriendlyType=Saved-Request Certificate (7/7/2015, 3:46:39
PM)&ThumbPrint=&TargetStoreFlags=0&SaveCert=yes
重新编码:(URLEncode1, URLEncode2, URLEncode3):
Mode%3Dnewreq%26CertRequest%3D-----BEGIN+CERTIFICATE+REQUEST-----+MIIDBjCCAe4CAQAwaDELMAkGA1UEBhMCQVUxDDAKBgNVBAgTA05TVzEPMA0GA1UE+BxMGU3lkbmV5MQwwCgYDVQQKEwNZdW0xDjAMBgNVBAsTBVl1bUlTMRwwGgYDVQQD+ExN0ZXN0LmF1LmludC50Z3IubmV0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB+CgKCAQEAygZvKhfs0mw4tModevTxOIz7eYYM%2B1axNv8FqoNyKr7xtqSbOMiNzf8R3rZ+4cTcu5nv7oC7GHPMhnF7AdsO4XexwnKfnCkofECGkO6O4oTmRfUPLa38nV1%2BmytB+lrQAl272jQdM9LSxTYW0OR9qO4mjAH1tvLF3IcC1OKOh6UNubdRFfE7dEXWnk%2BSF+M8tgl0t3SFsRxrZL3vkgL%2B%2FEmvdOKXeoIey%2F7UMNeWRcwTkS1mw30HjvitJdQGZi+gYJ6ldXrrITVKe9QXvVTxSl9NfzPHYp4yf%2FZvAJQmGLZ16aQo0PBeEfjkgkrcY5j+MnVI2Q8yC%2BW9Bg%3D%3D+-----END+CERTIFICATE+REQUEST-----%26CertAttrib%3DCertificateTemplate%3A%2AWebServer+UserAgent%3AMozilla%2F5.0+%28Windows+NT+6.3%3B+WOW64%3B+Trident%2F7.0%3B+rv%3A11.0%29+like+Gecko+%26FriendlyType%3DSaved-Request+Certificate+%287%2F7%2F2015%2C+3%3A46%3A39+PM%29%26ThumbPrint%3D%26TargetStoreFlags%3D0%26SaveCert%3Dyes
上面链接的三个网站(重新编码)都无法正确重新编码。
棘手的部分是“=”和“&”不应该被编码。
URL Encode Simple:
CR LF %0D%0A (Not %)
Space + (Not %20)
- - (Not %2D)
& & (Not %26)
= = (Not %3D)
+ (in CSR) %2B
\ (in CSR) %2F
( %28
) %29
我可以具体地使用sed这个例子,但我想知道是否有办法知道服务器期望的编码,并编码在正确的字符集中 自动 。这可能吗?
这是 Windows (CYGWIN) 上的 bash 脚本:
#!/bin/bash
#############################################################################################
# AUTHOR: FlORIAN BIDABE #
# #
# VERSION 2.0 RELEASE DATE February 07, 2018 #
# This script helps you with generating SSL material from an internal Micorosft CA #
# 1) Define your variables and CA Bundle in this script (between < and >) #
# 2) Run the script #
# #
# Process: #
# 1- Generate or import CSR #
# 2- Submit CSR and specify additional Subject Alternate Name (SAN) #
# 3- Collect certificate from your CA (Certificate Authority) ==> MANUAL #
# 4- Generate SSL material and format #
# #
# #
# Tested on: #
# Certificate Authority: Windows Server 2008 R2 / 2012 #
# Client: Windows 8.1 and Windows 10 with cygwin (cURL, OpenSSL, clip) #
#############################################################################################
#_____________________________________________________________________________________________
######################################## Variables ########################################
# Internal Env Settings
MSCA='server.domain.tld' # Internal Microsoft Certification Authority FQDN
CertTplt='WebServer' # Internal Cert Template Name
UA='Mozilla%2F5.0+%28Windows+NT+6.3%3B+WOW64%3B+Trident%2F7.0%3B+rv%3A11.0%29+like+Gecko'
Domain='localdomain' # Used for signing both hostname and FQDN
Username=""$Domain"\userid" # Required for certificate submission
#Password='WH4t3v3r' # Can be commented to be interactive
# Email Settings (Unauthenticated in my case)
mailserver="mailserver.com" # Mailserver FQDN
mailport=25 # Might need SSL if 465, 587
to="ServiceDesk@company.com"
cc="who.ever@company.com"
bcc="yourself@company.com,fortrackingpurpose@company.com"
MailTemplate="
Hello,
Please create and assign a ticket to track this certificate request from our market.
The Request ID has been attached in the email (HTTP Response)
Date: `date "+%Y-%m-%d %H:%M"`
Issuer: "$Username"
Information Systems
Phone number
Company Pty Ltd
Address and contact details"
# SaveIn=~/Desktop/Certs
SaveIn=~/Certificates/NewRequests # Save the file in Team's OneDrive folder mapped with ln using cygwin
FileMgr=explorer # File Manager
# OpenSSL CFG settings for CSR (Code Signing Request) submission
Country='AU'
State='NSW'
City='Sydney'
Company='Company'
UrOrg='Information Systems'
# Internal Base64 Root and Intermediate CAs (Used for creating PEM and PKCS12 bundles)
IntRoot=`echo '
-----BEGIN CERTIFICATE-----
<Intermediate>
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
<Root>
-----END CERTIFICATE-----'`
#_____________________________________________________________________________________________
######################################## Requirements ########################################
# OpenSSL
type openssl > /dev/null 2>&1 || {
echo "Cannot find OpensSSL, it is required to generate certificates. Aborting..." 1>&2
exit 1
}
# cURL
type curl > /dev/null 2>&1 || {
echo "Cannot find cURL, it is required to submit certificates. Aborting..." 1>&2
exit 1
}
#_____________________________________________________________________________________________
######################################## Optional ############################################
# Clip
type clip > /dev/null 2>&1 || {
echo -e "Cannot find clip ! it is required to save the CSR into your clipboard.\n Attempting to install it in System32..." 1>&2
cd 'C:\Windows\system32'; curl -L -O "https://www.dropbox.com/s/cvkxeak0j0wtjj0/clip.exe"
}
# GNU Email
type email > /dev/null 2>&1 || {
echo -e "Cannot find GNU email ! it is required to send an email to notify a security administrator and issue the certificate." 1>&2
}
# Internet Explorer
if [ -f '/cygdrive/c/Program\ Files/Internet\ Explorer/iexplore.exe' ]; then iexplore='/cygdrive/c/Program\ Files/Internet\ Explorer/iexplore.exe'
else iexplore=$(sed 's| |\ |g' <<< "$(find /cygdrive/ -name "iexplore.exe" -exec sh -c 'printf "%s\n" ""; kill "$PPID"' bash {} \;)")
fi
#_____________________________________________________________________________________________
######################################## Functions ########################################
gencsr() {
# Generate Config File (CFG) for Code Signing Request (CSR)
echo "`date "+%Y-%m-%d %H:%M:%S"` - User Option: 1) Generate CSR and Private Key" >> $LOGS
echo "`date "+%Y-%m-%d %H:%M:%S"` - Parsing Config File (CFG)" >> $LOGS
# Set additional SAN (for CFG)
local n=1 #Enter Loop
local SAN
SAN="subjectAltName = DNS:"$Hostname", DNS: "$Hostname.$Domain""
while (( n > 0 && n < 4 )); do
echo -e "\n\n\nDo you want to set an additional Subject Alternate Name (Config File) ? (No)"
echo -e "Current SAN:\n"$SAN""
echo -e "Select your choice and press [ENTER]\n\t[1] Add an IP address\n\t[2] Add an hostname\n\t[3] Reset SAN to default\n\t[*] Continue"
read -p "Option number : " n
case $n in
1) # Add Extra IP for SAN
while [[ -z ${IP+x} || $? != 0 ]]; do
read -p "What is the server's IP address: " IP
[[ "$IP" =~ ^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]).){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$ ]]
if [ $? != 0 ]; then echo "This IP address ("$IP") does not look quite right! Please try again..."; fi
[[ "$IP" =~ ^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]).){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$ ]]
done
SAN+=", IP:"$IP", DNS:"$IP""; unset IP
;;
2) # Add extra DNS name to SAN
while [[ -z ${extraSAN+x} || $? != 0 ]]; do
read -p "Specify a Fully Qualified Domain Name for the extra SAN : " extraSAN
[[ "$extraSAN" =~ ^[A-Za-z0-9.-]+$ ]]
if [ $? != 0 ]; then echo "This syntax is incorrect! Please try again..."; fi
[[ "$extraSAN" =~ ^[A-Za-z0-9.-]+$ ]]
done
SAN+=", DNS:"$extraSAN""; unset extraSAN
;;
3) SAN="subjectAltName = DNS:"$Hostname", DNS:"$Hostname.$Domain"" ;;
*) n=4 ;; #Quit loop
esac
done
echo "`date "+%Y-%m-%d %H:%M:%S"` - Subject Alternate Name (CFG): "$SAN"" >> $LOGS
echo "
[ req ]
default_md = sha512
default_bits = 2048
default_keyfile = "$Hostname"_pk8.key
distinguished_name = req_distinguished_name
encrypt_key = no
prompt = no
string_mask = nombstr
req_extensions = v3_req
input_password = password
output_password = password
[ v3_req ]
basicConstraints = CA:false
keyUsage = digitalSignature, keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth, clientAuth
"$SAN"
[ req_distinguished_name ]
countryName = "$Country"
stateOrProvinceName = "$State"
localityName = "$City"
0.organizationName = "$Company"
organizationalUnitName = "$UrOrg"
commonName = "$Hostname.$Domain"" > "$Hostname".cfg
echo "`date "+%Y-%m-%d %H:%M:%S"` - Config File (CFG) parsed ! Located at `pwd`/"$Hostname".cfg" >> $LOGS
# Generate CSR and private key (PKCS8) & convert Private Key (PKCS8 to PKCS1)
echo -e "\n\nGenerating Code Signing Request (CSR) and Private Key (PKCS#8)..."
echo "`date "+%Y-%m-%d %H:%M:%S"` - Generating Code Signing Request (CSR) and Private Key (PKCS#8): "$Hostname".csr and "$Hostname"_pk8.key" >> $LOGS
openssl req -out "$Hostname".csr -new -nodes -config "$Hostname".cfg > /dev/null 2>&1
echo "Generating private key (PKCS#1)..."
echo "`date "+%Y-%m-%d %H:%M:%S"` - Generating Private Key (PKCS#1): "$Hostname"_pk1.key" >> $LOGS
openssl rsa -in "$Hostname"_pk8.key -out "$Hostname"_pk1.key > /dev/null 2>&1
if [ $? != 0 ]; then
echo "An error has occured ! Exiting..., Please consult the logs"
echo "`date "+%Y-%m-%d %H:%M:%S"` - Error on generating CSR or Private Keys" >> $LOGS
exit 1
fi
}
importcsr() {
# Importing Code Signing Request (CSR)
echo "`date "+%Y-%m-%d %H:%M:%S"` - User Option: 2) Import CSR" >> $LOGS
local n
printf "3c"
echo -e "This function automates IIS7 certificate generation for "$Company $UrOrg"
\tServer name:\t"$Hostname"\n\tFQDN:\t\t"$Hostname"."$Domain"\n"
echo "Importing Code Signing Request..."
#Verify CSR
# If CSR is not Base 64
openssl req -text -noout -verify -in *.csr > /dev/null 2>&1
while [ $? != 0 ]; do
# Check if there are multiple csr files
while [ $(find -name "*.csr" | wc -l) != 1 ]; do
echo -e "\nError, $(find -name "*.csr" | wc -l) CSR(s) found ! One CSR is required..."
echo "Please import your CSR in "$SaveIn" and make sure the extension is *.csr"
echo "`date "+%Y-%m-%d %H:%M:%S"` - WARNING: There should be one CSR only in "$SaveIn"" >> $LOGS
$FileMgr . 2> /dev/null
read -p "Press any key to continue...";
done
openssl req -text -noout -verify -inform DER -in *.csr > /dev/null 2>&1
if [ $? == 0 ]; then
echo -e "\n\nThis Code Signing Request is not a Base64 request !\nConverting DER request to Base64... Success !"
mv *.csr "$Hostname".dcsr
openssl req -out "$Hostname".csr -outform PEM -inform DER -in *.dcsr
echo "`date "+%Y-%m-%d %H:%M:%S"` - DER CSR detected, converting to Base64... Success !" >> $LOGS
echo "`date "+%Y-%m-%d %H:%M:%S"` - DER CSR: "$Hostname".dcsr\tBase64 CSR: "$Hostname".csr" >> $LOGS
else
openssl req -text -noout -verify -in *.csr > /dev/null 2>&1
if [ $? != 0 ]; then
echo -e "Your CSR file is not valid or is corrupted!\nPlease import your CSR in "$SaveIn"..."
echo "`date "+%Y-%m-%d %H:%M:%S"` - ERROR: This CSR is invalid, it is neither a DER or Base64 CSR" >> $LOGS
$FileMgr . 2> /dev/null
read -p "Press any key to continue..."; fi
fi
openssl req -text -noout -verify -in *.csr > /dev/null 2>&1
done
# Optional: Converting a Base64 CSR to DER
if [ ! -f *.dcsr ]; then
openssl req -outform DER -inform PEM -in *.csr -out "$Hostname".dcsr > /dev/null 2>&1
if [ $? == 0 ]; then
echo "`date "+%Y-%m-%d %H:%M:%S"` - Base64 CSR detected, converting to DER... Success !" >> $LOGS
echo "`date "+%Y-%m-%d %H:%M:%S"` - DER CSR: "$Hostname".dcsr\tBase64 CSR: "$Hostname".csr" >> $LOGS
fi
fi
}
urlencode() {
local data
if [[ $# != 1 ]]; then return 1; fi
data="$(curl -s -o /dev/null -w %{url_effective} --get --data-urlencode "" "")"
if [[ $? != 3 ]]; then return 2; fi
echo "${data##/?}"; return 0
}
getcert() {
######################### 3- Get Certificate ########################
echo -e "\n\n`date "+%Y-%m-%d %H:%M:%S"` - Step 3: Getting the Certifiate" >> $LOGS
printf "3c"
echo -e "This function automates IIS7 certificate generation for "$Company $UrOrg"
\tServer name:\t"$Hostname"\n\tFQDN:\t\t"$Hostname"."$Domain"\n"
echo -e "Open \"Certificate Authority\" in a Management Console (MMC) and connect to "$MSCA"\nVerify that your certificate request is in "Pending Requests".\nIssue the Certificate (Right Click, All Tasks, Issue)\nNavigate to "Issue Certificates", order by Request ID (Descending) and export it (Open / Details / Copy To File) 'Base-64 Encoded X.509' to "$SaveIn".\nThe file must have a *.cer extension\n"
read -p "Press any keys when the certificate (*.cer) has been place in "$SaveIn""
#Verify Certificate
openssl x509 -text -noout -in "$Hostname".cer > /dev/null 2>&1
while [ $? != 0 ]; do
# Verify that there is only one certificate
while [ $(find -name "*.cer" | wc -l) == 0 ]; do
echo "Please import certificate (*.cer) in "$SaveIn""
if [ -z ${Manual+x} ]; then $FileMgr . 2> /dev/null
else
#If the certificate has been uploaded using a browser, it can be retrieved using the browser
if [ -z ${iexplore+x} ]; then echo "Open "https://"$MSCA"/certsrv/certckpn.asp""
else eval $iexplore "https://"$MSCA"/certsrv/certckpn.asp"; fi
fi
read -p "Press any key to continue..."; done
while [ $(find -name "*.cer" | wc -l) != 1 ]; do
echo "Error, $(find -name "*.cer" | wc -l) certificates found in "$SaveIn"! Please clean it up !"
$FileMgr . 2> /dev/null
read -p "Press any key to continue..."
done
# Verify Certificate Integrity and format
mv *.cer "$Hostname".cer
echo -e "`date "+%Y-%m-%d %H:%M:%S"` - Certificate found at `pwd`/"$Hostname".cer" >> $LOGS
openssl x509 -text -noout -in *.cer > /dev/null 2>&1
if [ $? != 0 ]; then
openssl x509 -inform der -text -noout -in *.cer > /dev/null 2>&1 # Test if DER
if [ $? == 0 ]; then # Convert DER to Base64
mv *.cer "$Hostname".der
openssl x509 -inform der -in "$Hostname".der -out "$Hostname".cer > /dev/null 2>&1
echo "`date "+%Y-%m-%d %H:%M:%S"` - DER certificate detected, converting to Base64... Success !" >> $LOGS
echo "`date "+%Y-%m-%d %H:%M:%S"` - DER certificate: "$Hostname".der\tBase64 certificate: "$Hostname".cer" >> $LOGS
else
echo -e "This certificate is invalid or corrupted!\nPlease import it again in "$SaveIn"..."
echo "`date "+%Y-%m-%d %H:%M:%S"` - ERROR: The certificate is invalid, it is neither a DER or Base64 certificate" >> $LOGS
read -p "Press any key to continue..."
fi
openssl x509 -text -noout -in *.cer > /dev/null 2>&1
fi
done
# Optional: Converting a Base64 CSR to DER
if [ ! -f *.der ]; then
openssl x509 -outform der -in "$Hostname".cer -out "$Hostname".der > /dev/null 2>&1
if [ $? == 0 ]; then
echo "`date "+%Y-%m-%d %H:%M:%S"` - Base64 Certificate detected, converting to DER... Success !" >> $LOGS
echo "`date "+%Y-%m-%d %H:%M:%S"` - DER Certificate: "$Hostname".dcsr\tBase64 Certificate: "$Hostname".csr" >> $LOGS
fi
fi
###################### 4- Generating SSL material #########################
# Creating PEM certificate chain
echo -e "`date "+%Y-%m-%d %H:%M:%S"` - Step 4 (Final): Generating SSL material" >> $LOGS
if [ -f ""$Hostname"_pk1.key" ]; then
cat "$Hostname"_pk1.key > ""$Hostname".pem"
cat *.cer >> ""$Hostname".pem"
echo -e "`date "+%Y-%m-%d %H:%M:%S"` - A PEM has been generated containing the Private Key and entire certificate chain: Public Key for "$Hostname" and CA Bundle (intermediate and root certificates) " >> $LOGS
else
cat *.cer > ""$Hostname".pem"
echo -e "`date "+%Y-%m-%d %H:%M:%S"` - A PEM has been generated containing the entire certificate chain: Public Key for "$Hostname" and CA Bundle (intermediate and root certificates)" >> $LOGS
echo -e "`date "+%Y-%m-%d %H:%M:%S"` - As the CSR was imported, no private key can be included in the PEM container" >> $LOGS
fi
echo "$IntRoot" >> ""$Hostname".pem"
sed -i '/^$/d' "$Hostname".pem"" # Delete empty lines
# Converting PEM certificate chain to PKCS#12 (.pfx)"
cat *.pfx 2> /dev/null #Enter Loop
while [ $? != 0 ]; do
if [ -f "$Hostname"_pk1.key ]; then openssl pkcs12 -export -out ""$Hostname".pfx" -in ""$Hostname".pem"
else openssl pkcs12 -export -nokeys -out ""$Hostname".pfx" -in ""$Hostname".pem"
fi
done
echo -e "`date "+%Y-%m-%d %H:%M:%S"` - A PKCS12 (.pfx, .p12) has been generated from the PEM" >> $LOGS
echo -e "`date "+%Y-%m-%d %H:%M:%S"` - Ending gracefully :)" >> $LOGS
mv ../"$Hostname" ../../INTERNAL/
cd ../../INTERNAL/"$Hostname"
$FileMgr . 2> /dev/null
exit 0
}
#_____________________________________________________________________________________________
######################################## GUI ########################################
printf "3c"
echo -e "This function automates IIS7 certificate generation for "$Company $UrOrg""
# Set Hostname and IP address
Hostname=""; [[ "$Hostname" =~ ^[-A-Za-z0-9]+$ ]]
while [ $? != 0 ]; do
read -p "Specify the server hostname (Not FQDN !): " Hostname
[[ "$Hostname" =~ ^[-A-Za-z0-9]+$ ]]
if [ $? != 0 ]; then echo "This hostname syntax is incorrect, try again !"; fi
[[ "$Hostname" =~ ^[-A-Za-z0-9]+$ ]]
done
LOGS=""$Hostname".logs"
# Set destination folder for SSL material
SaveIn+="/"$Hostname"";
if [ -d "$SaveIn" ]; then
echo "A folder named "$Hostname" already exists, Start over (delete existing materials) or quit ?"
echo -e "Select your choice and press [ENTER]\n\t[1] Start Over (Delete existing content)\n\t[2] Resume (Certificate Generation)\n\t[*] Quit"
read -p "Option number : " n
case $n in
1) rm -R "$SaveIn" > /dev/null 2>&1; mkdir -p "$SaveIn" > /dev/null 2>&1; cd "$SaveIn" ;;
2) cd "$SaveIn"; getcert "$@" ;;
*) echo "Aborting..."; exit 0 ;;
esac
else mkdir -p "$SaveIn"; cd "$SaveIn"
fi
###LOGGING GUI###
echo "`date "+%Y-%m-%d %H:%M:%S"` - Starting... Path: `pwd`" > $LOGS
echo "`date "+%Y-%m-%d %H:%M:%S"` - OpenSSL Version: `openssl version`" >> $LOGS
echo "`date "+%Y-%m-%d %H:%M:%S"` - cURL Version: `head -n 1 <(curl --version)`" >> $LOGS
echo "`date "+%Y-%m-%d %H:%M:%S"` - Server name: "$Hostname" FQDN: "$Hostname"."$Domain"" >> $LOGS
######################### 1- Get CSR ###############################
echo -e "\n\n`date "+%Y-%m-%d %H:%M:%S"` - Step 1: Code Signing Request" >> $LOGS
printf "3c"
echo -e "This function automates IIS7 certificate generation for "$Company $UrOrg"
\tServer name:\t"$Hostname"\n\tFQDN:\t\t"$Hostname"."$Domain"\n"
echo -e "\nCode Signing Request (CSR):\n\tYou can generate a CSR and Private key or import a CSR (generated by an appliance and downloaded by you).
\tPlease note that importing a CSR means that the private key remains on the appliance or vendor's site.
\tSelect your choice and press [ENTER]\n\t[1] Generate CSR and Private Key\n\t[2] Import CSR\n\t[*] Quit"
read -p "Option number : " n
case $n in
1) gencsr "$@" ;;
2) importcsr "$@" ;;
*) echo "`date "+%Y-%m-%d %H:%M:%S"` - User Option: Quit" >> $LOGS; echo "Aborting..."; exit 0 ;;
esac
######################### 2- Submit CSR ############################
echo -e "\n\n`date "+%Y-%m-%d %H:%M:%S"` - Step 2: Submitting CSR" >> $LOGS
# Capture Attempt: Session ID cookie
echo "`date "+%Y-%m-%d %H:%M:%S"` - Capturing Session ID cookie from "$MSCA"" >> $LOGS
echo 'Capturing ASP Session ID (Cookie)...'
if [ -z "$Password" ]; then echo "What is the password for $Username ?: "; read -s Password; fi
RE=': ([^;]*);' #Regex to capture ASP Session ID from cookie string
while read l; do [[ $l =~ $RE ]] && AspSession="${BASH_REMATCH[1]}"; done <<<"$(grep "Cookie" <<< "$(curl --silent -Iku "$Username":"$Password" --ntlm https://"$MSCA"/certsrv/certrqxt.asp)")"
# If fail capturing cookie ==> Manual (Browser-Mode)
if [ -z "$AspSession" ]; then
echo "`date "+%Y-%m-%d %H:%M:%S"` - ERROR: Cannot capture Session ID cookie, failover to browser-mode..." >> $LOGS
echo "WARNING: Cannot capture Session ID cookie for "$MSCA", failover to browser-mode...\nPlease verify your credentials to connect to $MSCA\n\n"
echo "Paste CSR directly in internal CA web interface"
echo -e "\tConfirm the Subject Alternate Name field before submission !\n\tNote that the CSR may already include SAN(s) !
Current Subject: `openssl req -in *.csr -noout -text | grep "Subject:"`
Current SAN: `openssl req -in *.csr -noout -text | grep "DNS:"`"
clip <<< "$(cat *.csr 2> /dev/null)" ; Manual=1
echo -e "Please upload your Code Signing Request to your Internal Certificate Authority ("$MSCA") :"
if [ -z ${iexplore+x} ]; then
echo "Open "https://"$MSCA"/certsrv/certrqxt.asp" in a browser"
else
eval $iexplore "https://"$MSCA"/certsrv/certrqxt.asp" &
echo "Press any key to continue..." ; read
fi
fi
# If Session ID cookie sucessfully captured ==> Automatic (cURL-Mode)
if [ -z ${Manual+x} ]; then
echo "ASP cookie captured !"
# Set additional SAN (for cURL)
echo -e "\n\nConfirm the Subject Alternate Name before submission:
Current Common Name: `openssl req -in *.csr -noout -text | grep "Subject:"`
Current SAN: `openssl req -in *.csr -noout -text | grep "DNS:"`"
echo -e "\nDo you want to add a Subject Alternate Name (No) ?\nSelect your choice and press [ENTER]\n\t[1] Yes\n\t[*] No\n"
read -p "Option number : " n
case $n in
1) unset n; n=1 #Enter Loop
unset SAN; SAN="san%3Adns%3D"$Hostname"%26dns%3D"$Hostname.$Domain""
while (( n > 0 && n < 4 )); do
echo -e "\n\n\nDo you want to set an additional Subject Alternate Name ? (No)"
echo -e "Current SAN (URL Encoded): "$SAN""
echo -e "Select your choice and press [ENTER]\n\t[1] Add an IP address\n\t[2] Add an hostname\n\t[3] Reset SAN to default\n\t[*] Continue"
read -p "Option number : " n
case $n in
1) # Add Extra IP for SAN
while [[ -z ${IP+x} || $? != 0 ]]; do
read -p "What is the server's IP address: " IP
[[ "$IP" =~ ^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]).){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$ ]]
if [ $? != 0 ]; then echo "This IP address ("$IP") does not look quite right! Please try again..."; fi
[[ "$IP" =~ ^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]).){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$ ]]
done
SAN+="%26dns%3D"$IP""; unset IP
;;
2) # Add extra DNS name to SAN
while [[ -z ${extraSAN+x} || $? != 0 ]]; do
read -p "Specify a Fully Qualified Domain Name (FQDN) for the extra SAN: " extraSAN
[[ "$extraSAN" =~ ^[A-Za-z0-9.-]+$ ]]
if [ $? != 0 ]; then echo "This syntax is incorrect! Please try again..."; fi
[[ "$extraSAN" =~ ^[A-Za-z0-9.-]+$ ]]
done
SAN+="%26dns%3D"$extraSAN""; unset extraSAN
;;
3) SAN="san%3Adns%3D"$Hostname"%26dns%3D"$Hostname.$Domain"" ;;
*) n=4 ; SAN+='%0D%0A' ;; #Quit loop
esac
done
;;
*) ;;
esac
CertFormat=$(sed 's| |+|g' <<< $(sed 's|+|%2B|g' <<< $(sed 's|/|%2F|g' <<< $(sed ':a;N;$!ba;s/\n/%0D%0A/g' *.csr))))
Date=$(sed 's|%20|+|g' <<< $(urlencode "`date '+%m/%d/%Y,%r'`"))
cURLData="Mode=newreq&CertRequest="$CertFormat"&CertAttrib="$SAN"CertificateTemplate%3A"$CertTplt"%0D%0AUserAgent="$UA"%0D%0A&FriendlyType=Saved-Request+Certificate+%28"$Date"%29&ThumbPrint=&TargetStoreFlags=0&SaveCert=yes"
echo "`date "+%Y-%m-%d %H:%M:%S"` - Generating and encoding cURL POST data..." >> $LOGS
echo -e "Injecting crafted POST request to Internal CA using cURL and NTLM authentication...\n"
echo "`date "+%Y-%m-%d %H:%M:%S"` - Injecting crafted POST request to Internal CA using cURL and NTLM authentication..." >> $LOGS
InjectCmd="curl --silent -i -ku '$Username':'$Password' --ntlm '"https://"$MSCA"/certsrv/certfnsh.asp"' \
-H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' \
-H 'Accept-Encoding: gzip, deflate' \
-H 'Accept-Language: en-US,en;q=0.5' \
-H 'Connection: keep-alive' -H 'Cookie: "$AspSession"' \
-H 'Host: "$MSCA"' \
-H 'Referer: https://"$MSCA"/certsrv/certrqxt.asp' \
-H 'User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko' \
-H 'Content-Type: application/x-www-form-urlencoded' --data '"$cURLData"'"
InjectCmdLog=`echo $InjectCmd | sed "s|"$Password"|<password>|g"`
echo "`date "+%Y-%m-%d %H:%M:%S"` - Command: "$InjectCmdLog"" >> $LOGS
echo "`date "+%Y-%m-%d %H:%M:%S"` - BEGIN HTTP REPLY: Consult "$Hostname".html" >> $LOGS
eval "$InjectCmd" &> "$Hostname.html"
echo "`date "+%Y-%m-%d %H:%M:%S"` - END HTTP REPLY" >> $LOGS
if [ $? != 0 ] || grep -q 'Access Denied' "$Hostname.html" || grep -q 'Denied by Policy Module' "$Hostname.html"; then
echo -e "Injection seems to have gone wrong! Please verify if the request is missing in the Certificate Authority Snap-In on "$MSCA""
echo -e "Consult Log file for analysis of the cURL query: it might be malformed!"
echo -e "Log file location: `pwd`/"$LOGS""
echo "`date "+%Y-%m-%d %H:%M:%S"` - Injection has failed !" >> $LOGS
exit 1
fi
fi
email "$to" -cc "$cc" -bcc "$bcc" -a "$Hostname".html -s "Certificate Request: Please issue $Hostname.$Domain certificate" -r $mailserver -p $mailport <<< "$MailTemplate"
echo "An email has been sent to the US (You are in CC) ! Once approved, please connect to "$MSCA" to retrieve your certificate using the Certificate Authority via mmc.exe"
echo "Once retrieved, open again this utility, enter the same hostname ("$Hostname") and resume operations: this will generates cryptographic material bundles (PEM, #PKCS12... etc.)"
echo "Please take notes of password you set to access the private key on the PKCS12 material"
我在 bash 上解决了 linux 和 curl:
#!/bin/sh
# tested on SUSE Linux 12 SP1
# - CN Object name
# - username
# - password
MSCA='HOSTNAME' # Internal Microsoft Certification Authority
Username=
Password=
function show_usage()
{
echo "Scrip for retrive certificate from MS SubCA"
echo "Usage: [=10=] <CN> [domain\\username] [password]"
echo " "
echo "Example: [=10=] example.com workgroup\\foo bar"
exit 0
}
if [ -z "" ]
then
show_usage
exit 0
fi
if [ -z "" ]
then
Username="workgroup\foo"
Password="bar"
fi
echo -e "\e[32m1. Generate private key...\e[0m"
openssl req -new -nodes -out .pem -keyout .key -subj "/C=RU/ST=State/L=City/O=Org/CN=/emailAddress=postmaster@example.com"
CERT=`cat .pem | tr -d '\n\r'`
DATA="Mode=newreq&CertRequest=${CERT}&C&TargetStoreFlags=0&SaveCert=yes"
CERT=`echo ${CERT} | sed 's/+/%2B/g'`
CERT=`echo ${CERT} | tr -s ' ' '+'`
CERTATTRIB="CertificateTemplate:Server%0D%0A"
echo -e "\e[32m2. Request cert...\e[0m"
OUTPUTLINK=`curl -k -u "${Username}":${Password} --ntlm \
"https://${MSCA}/certsrv/certfnsh.asp" \
-H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' \
-H 'Accept-Encoding: gzip, deflate' \
-H 'Accept-Language: en-US,en;q=0.5' \
-H 'Connection: keep-alive' \
-H "Host: ${MSCA}" \
-H "Referer: https://${MSCA}/certsrv/certrqxt.asp" \
-H 'User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko' \
-H 'Content-Type: application/x-www-form-urlencoded' \
--data "Mode=newreq&CertRequest=${CERT}&CertAttrib=${CERTATTRIB}&TargetStoreFlags=0&SaveCert=yes&ThumbPrint=" | grep -A 1 'function handleGetCert() {' | tail -n 1 | cut -d '"' -f 2`
CERTLINK="https://${MSCA}/certsrv/${OUTPUTLINK}"
echo -e "\e[32m3. Retrive cert: $CERTLINK\e[0m"
curl -k -u "${Username}":${Password} --ntlm $CERTLINK \
-H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' \
-H 'Accept-Encoding: gzip, deflate' \
-H 'Accept-Language: en-US,en;q=0.5' \
-H 'Connection: keep-alive' \
-H "Host: ${MSCA}" \
-H "Referer: https://${MSCA}/certsrv/certrqxt.asp" \
-H 'User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko' \
-H 'Content-Type: application/x-www-form-urlencoded' > .crt
echo -e "\e[32m4. Verifying cert for \e[0m"
openssl verify -verbose .crt
if [ "0" -eq "$?" ] ;
then
echo -e "\e[32mWell done. Have a nice day.\e[0m"
exit 0
else
echo -e "\e[31;47mError code: $?. Stopping.\e[0m"
exit 1
fi
这是我从论坛帖子(包括这篇帖子)中借用的部分以及我自己完成的一些内容的组合。它有一些东西可以容纳 Aruba Instant AP 和它接受的证书格式。专为满足我实验室的需求而量身定制。
这里的答案很好,@SkazochNik J 提供了最后一块(自动提交 csr 并检索证书)。 @SkazochNik 如果你碰巧看到这个,我要找的最后一件事就是通过 curl/bash 从 CA 中提取 CA 证书。如果你碰巧知道那里的格式,那就太棒了......
如果这有用,我构建的(到目前为止):
#!/usr/bin/env bash
MSCA='dc1.myDomain.com' # Internal Microsoft Certification Authority
Username=<domain\user>
Password=<pass>
echo "-- Certificate csr and key generator --"
echo "-- all certificates use myDomain.com domain --"
echo " "
echo "Is this certificate for a wireless controller/vc [y/n]"
read _isWlan
echo "provide all hostnames to be used as the CN first then additional SAN values (only the hostname)"
read _host1 _host2 _host3 _host4 _host5
echo "provide all IP addresses desired as SAN values"
read _ip1 _ip2 _ip3 _ip4 _ip5
if [ ${_isWlan,,} == 'y' ] || [ ${_isWlan,,} == 'yes' ]; then _isWlan=true; fi
if [ -z "$_host2" ]; then _dns2=false; else _dns2=true; fi
if [ -z "$_host3" ]; then _dns3=false; else _dns3=true; fi
if [ -z "$_host4" ]; then _dns4=false; else _dns4=true; fi
if [ -z "$_host5" ]; then _dns5=false; else _dns5=true; fi
if [ -z "$_ip2" ]; then _ip2in=false; else _ip2in=true; fi
if [ -z "$_ip3" ]; then _ip3in=false; else _ip3in=true; fi
if [ -z "$_ip4" ]; then _ip4in=false; else _ip4in=true; fi
if [ -z "$_ip5" ]; then _ip5in=false; else _ip5in=true; fi
echo "[req]" > $_host1.cnf
echo "default_bits = 2048" >> $_host1.cnf
echo "prompt = no" >> $_host1.cnf
echo "default_md = sha256" >> $_host1.cnf
echo "req_extensions = req_ext" >> $_host1.cnf
echo "distinguished_name = dn" >> $_host1.cnf
echo " " >> $_host1.cnf
echo "[ dn ]" >> $_host1.cnf
echo "C=US" >> $_host1.cnf
echo "ST=Indiana" >> $_host1.cnf
echo "L=Noblesville" >> $_host1.cnf
echo "O=WadeLab" >> $_host1.cnf
echo "OU=Engineering" >> $_host1.cnf
echo "emailAddress=wade1@hpe.com" >> $_host1.cnf
if $_isWlan; then
echo "CN = securelogin.myDomain.com" >> $_host1.cnf
else
echo "CN = "$_host1".myDomain.com" >> $_host1.cnf
fi
echo " " >> $_host1.cnf
echo "[ req_ext ]" >> $_host1.cnf
echo "subjectAltName = @alt_names" >> $_host1.cnf
echo " " >> $_host1.cnf
echo "[ alt_names ]" >> $_host1.cnf
# it would be prettier to populate an array from the input and loop through them, but it would take me longer
# to refresh my knowledge for the bash way to do that then it did to copy paste all this
if $_isWlan; then
echo "DNS.1 = securelogin.myDomain.com" >> $_host1.cnf
echo "DNS.2 = "$_host1".myDomain.com" >> $_host1.cnf
echo "DNS.3 = "$_host1 >> $_host1.cnf
if $_dns2; then
echo "DNS.4 = "$_host2".myDomain.com" >> $_host1.cnf
fi
if $_dns3; then
echo "DNS.5 = "$_host3".myDomain.com" >> $_host1.cnf
fi
if $_dns4; then
echo "DNS.6 = "$_host4".myDomain.com" >> $_host1.cnf
fi
if $_dns5; then
echo "DNS.7 = "$_host5".myDomain.com" >> $_host1.cnf
fi
else
echo "DNS.1 = "$_host1".myDomain.com" >> $_host1.cnf
echo "DNS.2 = "$_host1 >> $_host1.cnf
if $_dns2; then
echo "DNS.3 = "$_host2".myDomain.com" >> $_host1.cnf
fi
if $_dns3; then
echo "DNS.4 = "$_host3".myDomain.com" >> $_host1.cnf
fi
if $_dns4; then
echo "DNS.5 = "$_host4".myDomain.com" >> $_host1.cnf
fi
if $_dns5; then
echo "DNS.6 = "$_host5".myDomain.com" >> $_host1.cnf
fi
fi
echo "IP.1 = "$_ip1 >> $_host1.cnf
if $_ip2in; then
echo "IP.2 = "$_ip2 >> $_host1.cnf
fi
if $_ip3in; then
echo "IP.3 = "$_ip3 >> $_host1.cnf
fi
if $_ip4in; then
echo "IP.4 = "$_ip4 >> $_host1.cnf
fi
if $_ip5in; then
echo "IP.5 = "$_ip5 >> $_host1.cnf
fi
echo
echo "1. Creating Certificate Request..."
openssl req -nodes -newkey rsa:2048 -keyout $_host1.key -out $_host1.csr -config $_host1.cnf
#echo "--- csr and key creation complete ---"
#echo " "
#echo "---------------------------"
#echo "-----Below is your CSR-----"
#echo "---------------------------"
#cat $_host1.csr
#echo
#echo
# >> Start Send csr to CA and retrieve certificate
CERT=`cat $_host1.csr | tr -d '\n\r'`
DATA="Mode=newreq&CertRequest=${CERT}&C&TargetStoreFlags=0&SaveCert=yes"
CERT=`echo ${CERT} | sed 's/+/%2B/g'`
CERT=`echo ${CERT} | tr -s ' ' '+'`
CERTATTRIB="CertificateTemplate:WebServerv2Exportable%0D%0A"
echo "2. Request cert from "$MSCA"..."
OUTPUTLINK=`curl -k -u "${Username}":${Password} --ntlm \
"https://${MSCA}/certsrv/certfnsh.asp" \
-H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' \
-H 'Accept-Encoding: gzip, deflate' \
-H 'Accept-Language: en-US,en;q=0.5' \
-H 'Connection: keep-alive' \
-H "Host: ${MSCA}" \
-H "Referer: https://${MSCA}/certsrv/certrqxt.asp" \
-H 'User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko' \
-H 'Content-Type: application/x-www-form-urlencoded' \
--data "Mode=newreq&CertRequest=${CERT}&CertAttrib=${CERTATTRIB}&TargetStoreFlags=0&SaveCert=yes&ThumbPrint=" | grep -A 1 'function handleGetCert() {' | tail -n 1 | cut -d '"' -f 2`
CERTLINK="https://${MSCA}/certsrv/${OUTPUTLINK}"
echo "3. Retrive cert: "$CERTLINK"..."
curl -k -u "${Username}":${Password} --ntlm $CERTLINK \
-H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' \
-H 'Accept-Encoding: gzip, deflate' \
-H 'Accept-Language: en-US,en;q=0.5' \
-H 'Connection: keep-alive' \
-H "Host: ${MSCA}" \
-H "Referer: https://${MSCA}/certsrv/certrqxt.asp" \
-H 'User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko' \
-H 'Content-Type: application/x-www-form-urlencoded' > $_host1.cer
echo "4. Verifying cert for "$_host1"..."
openssl verify -CAfile ca.cer -verbose $_host1.cer
if [ "0" -eq "$?" ] ;
then
echo "Certificate Validation Completed Succesfully"
echo
#exit 0
else
echo "Error code: "$?". Stopping."
exit 1
fi
#/END send csr to CA and retrieve certificate
if $_isWlan; then
echo "Do you need the certficate combined with the CA and key for Aruba IAP? [y/n]"
read _isIap
fi
if [ ${_isIap,,} == 'y' ] || [ ${_isIap,,} == 'yes' ]; then
echo "-------------------------------------------------------"
echo "----- Combining Server CA and Key file for VC -----"
echo "-------------------------------------------------------"
echo
# echo "-----Please Paste in the resulting PEM certificate-----"
# echo "----- then press [CTRL+D] to continue -----"
# echo "-------------------------------------------------------"
# _svrCert=$(</dev/stdin)
# echo "$_svrCert" > tmp.cer
# no error check right now for existing of CA.cer
mv $_host1.cer tmp.cer
cat ca.cer >> tmp.cer
cat $_host1.key >> tmp.cer
cat tmp.cer | sed '/^[[:space:]]*$/d' > $_host1.cer ##Remove blank lines
rm -f tmp.cer
echo "--------------------------------------------------"
echo "-----Cert Creation Complete. Combined cert ------"
echo "----- is in this directory "$_host1".cer ------"
echo "--------------------------------------------------"
else
echo "--------------------------------------------------"
echo "--------------------- DONE ---------------------"
echo "----- "$_host1".cer is in this directory ------"
echo "--------------------------------------------------"
fi
echo
echo Outputting Certificate Contents to Display...
sleep 4
clear
cat $_host1.cer
我在Java解决了。这是 class:
package com.qequipe.dsiglib.p10;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigInteger;
import java.net.Authenticator;
import java.net.HttpURLConnection;
import java.net.PasswordAuthentication;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.util.Base64;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSession;
import javax.security.auth.x500.X500Principal;
import org.spongycastle.operator.ContentSigner;
import org.spongycastle.operator.OperatorCreationException;
import org.spongycastle.operator.jcajce.JcaContentSignerBuilder;
import org.spongycastle.pkcs.PKCS10CertificationRequest;
import org.spongycastle.pkcs.PKCS10CertificationRequestBuilder;
import org.spongycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder;
import com.qequipe.dsiglib.util.FileUtil;
public class P10Generator {
public static byte[] generate(KeyPair pair) throws OperatorCreationException, IOException
{
//KeyPair pair = generateKeyPair();
PKCS10CertificationRequestBuilder p10Builder = new JcaPKCS10CertificationRequestBuilder(
new X500Principal("CN=Requested Test Certificate"), pair.getPublic());
JcaContentSignerBuilder csBuilder = new JcaContentSignerBuilder("SHA256withRSA");
ContentSigner signer = csBuilder.build(pair.getPrivate());
PKCS10CertificationRequest csr = p10Builder.build(signer);
return csr.getEncoded();
}
public static void main(String[] args)
{
try
{
KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA");
gen.initialize(2048);
KeyPair pair = gen.generateKeyPair();
byte[] pkcs10 = generate(pair);
String base64pkcs10 = new String(Base64.getEncoder().encode(pkcs10));
System.out.println(new BigInteger(1, pkcs10).toString(16));
System.out.println(base64pkcs10);
Date date = new Date();
Authenticator.setDefault(new Authenticator() {
@Override
public PasswordAuthentication getPasswordAuthentication() {
System.out.println("Scheme:" + getRequestingScheme());
return new PasswordAuthentication("\<username>", "password".toCharArray());
}
});
String request = "Mode=newreq&CertRequest=" + URLEncoder.encode(base64pkcs10) +
"&CertAttrib=" + URLEncoder.encode("CertificateTemplate:User\r\nUserAgent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36\r\n") +
"&FriendlyType=" + URLEncoder.encode("Saved-Request Certificate (" + (date.getDay()) + "/" + (date.getMonth() + 1) + "/" + date.getYear() + ", " + date.getHours() + ":" + date.getMinutes() + ":" + date.getSeconds() + ")") +
"&ThumbPrint=&TargetStoreFlags=0&SaveCert=yes";
byte[] cert = sendRequest("http://<yourcaurl>/certsrv/certfnsh.asp", request, "username", "password");
System.out.println(new BigInteger(1, cert).toString(16));
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
public static byte[] sendRequest(String urlString, String content, String username, String password) throws IOException {
HttpURLConnection con;
ByteArrayOutputStream out = new ByteArrayOutputStream();
URL url = new URL(urlString);
con = (HttpURLConnection) url.openConnection();
//String protocol = url.getProtocol();
con.setInstanceFollowRedirects(false);
con.setRequestMethod("POST");
//String encoded = Base64.getEncoder().encodeToString((username+":"+password).getBytes(StandardCharsets.UTF_8)); //Java 8
//con.setRequestProperty("Authorization", "NTML "+encoded);
con.setRequestProperty("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
con.setRequestProperty("Accept-Encoding","gzip, deflate");
con.setRequestProperty("Accept-Language", "en-US,en;q=0.5");
con.setRequestProperty("Connection","keep-alive");
con.setRequestProperty("Host", url.getHost());
con.setRequestProperty("Referer", url.getHost() + "/certsrv/certrqxt.asp");
con.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko");
con.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
con.setRequestProperty("Content-Length", "" + content.length());
con.setDoOutput(true);
OutputStream outs = con.getOutputStream();
outs.write(content.getBytes());
outs.flush();
BufferedInputStream bis = new BufferedInputStream(con.getInputStream());
int length;
while ((length = bis.read()) != -1) {
out.write(length);
}
out.close();
System.out.println(out);
int respCode;
System.out.println("RESP code = " + (respCode = con.getResponseCode()));
//System.out.println("RESPONSE = \n" + out);
if(con.getResponseCode() < HttpURLConnection.HTTP_BAD_REQUEST)
{
con.disconnect();
Pattern p = Pattern.compile("certnew.cer\?ReqID=(\d+)&");//. represents single character.
Matcher m = p.matcher(new String(out.toByteArray(), Charset.forName("UTF-8")));
if(m.find())
{
String reqid = m.group(1);
System.out.println(reqid);
URL certurl = new URL(url.getProtocol() +"://" + url.getHost() + "/certsrv/certnew.cer?ReqID=" + reqid + "&Enc=bin");
InputStream ins = certurl.openStream();
ByteArrayOutputStream bouts = new ByteArrayOutputStream();
FileUtil.copy(ins, bouts);
ins.close();
return bouts.toByteArray();
}
else
{
return null;
}
}
else
{
con.disconnect();
return null;
}
}
}
我已经编写了一个 bash 脚本来根据此 ServerFault link.
自动生成 IIS7 证书我想通过 cURL 自动将代码签名请求 (CSR) 发送到内部 Microsoft 证书颁发机构 (MS CA),以下代码很有前途并已成功将 CSR 提交给 MS CA:
$ curl -k -u '<Domain>\<Username>':<Password> --ntlm
'https://<InternalMSCA>/certsrv/certfnsh.asp'
-H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'
-H 'Accept-Encoding: gzip, deflate' -H 'Accept-Language: en-US,en;q=0.5'
-H 'Connection: keep-alive'
-H 'Host: <InternalMSCA>'
-H 'Referer: https://<InternalMSCA>/certsrv/certrqxt.asp'
-H 'User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko'
-H 'Content-Type: application/x-www-form-urlencoded'
--data 'Mode=newreq&CertRequest=-----BEGIN+CERTIFICATE+REQUEST-----%0D%0AMIIDBjCCAe4CAQAwaDELMAkGA1UEBhMCQVUxDDAKBgNVBAgTA05TVzEPMA0GA1UE%0D%0ABxMGU3lkbmV5MQwwCgYDVQQKEwNZdW0xDjAMBgNVBAsTBVl1bUlTMRwwGgYDVQQD%0D%0AExN0ZXN0LmF1LmludC50Z3IubmV0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB%0D%0ACgKCAQEAygZvKhfs0mw4tModevTxOIz7eYYM%2B1axNv8FqoNyKr7xtqSbOMiNzf8R3rZ%0D%0A4cTcu5nv7oC7GHPMhnF7AdsO4XexwnKfnCkofECGkO6O4oTmRfUPLa38nV1%2BmytB%0D%0AlrQAl272jQdM9LSxTYW0OR9qO4mjAH1tvLF3IcC1OKOh6UNubdRFfE7dEXWnk%2BSF%0D%0AM8tgl0t3SFsRxrZL3vkgL%2B%2FEmvdOKXeoIey%2F7UMNeWRcwTkS1mw30HjvitJdQGZi%0D%0AgYJ6ldXrrITVKe9QXvVTxSl9NfzPHYp4yf%2FZvAJQmGLZ16aQo0PBeEfjkgkrcY5j%0D%0AMnVI2Q8yC%2BW9Bg%3D%3D%0D%0A-----END+CERTIFICATE+REQUEST-----&CertAttrib=CertificateTemplate%3A*WebServer%0D%0AUserAgent%3AMozilla%2F5.0+%28Windows+NT+6.3%3B+WOW64%3B+Trident%2F7.0%3B+rv%3A11.0%29+like+Gecko%0D%0A&FriendlyType=Saved-Request+Certificate+%287%2F7%2F2015%2C+3%3A46%3A39+PM%29&ThumbPrint=&TargetStoreFlags=0&SaveCert=yes'
| firefox "data:text/html;base64,$(base64 -w 0 <&0)"
我有兴趣在修改后重播此请求:
- 解码--数据(确定)
- 修改--数据(确定)
- 重新编码...(不正确)
编码:
Mode=newreq&CertRequest=-----BEGIN+CERTIFICATE+REQUEST-----%0D%0AMIIDBjCCAe4CAQAwaDELMAkGA1UEBhMCQVUxDDAKBgNVBAgTA05TVzEPMA0GA1UE%0D%0ABxMGU3lkbmV5MQwwCgYDVQQKEwNZdW0xDjAMBgNVBAsTBVl1bUlTMRwwGgYDVQQD%0D%0AExN0ZXN0LmF1LmludC50Z3IubmV0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB%0D%0ACgKCAQEAygZvKhfs0mw4tModevTxOIz7eYYM%2B1axNv8FqoNyKr7xtqSbOMiNzf8R3rZ%0D%0A4cTcu5nv7oC7GHPMhnF7AdsO4XexwnKfnCkofECGkO6O4oTmRfUPLa38nV1%2BmytB%0D%0AlrQAl272jQdM9LSxTYW0OR9qO4mjAH1tvLF3IcC1OKOh6UNubdRFfE7dEXWnk%2BSF%0D%0AM8tgl0t3SFsRxrZL3vkgL%2B%2FEmvdOKXeoIey%2F7UMNeWRcwTkS1mw30HjvitJdQGZi%0D%0AgYJ6ldXrrITVKe9QXvVTxSl9NfzPHYp4yf%2FZvAJQmGLZ16aQo0PBeEfjkgkrcY5j%0D%0AMnVI2Q8yC%2BW9Bg%3D%3D%0D%0A-----END+CERTIFICATE+REQUEST-----&CertAttrib=CertificateTemplate%3A*WebServer%0D%0AUserAgent%3AMozilla%2F5.0+%28Windows+NT+6.3%3B+WOW64%3B+Trident%2F7.0%3B+rv%3A11.0%29+like+Gecko%0D%0A&FriendlyType=Saved-Request+Certificate+%287%2F7%2F2015%2C+3%3A46%3A39+PM%29&ThumbPrint=&TargetStoreFlags=0&SaveCert=yes
解码:
Mode=newreq&CertRequest=-----BEGIN CERTIFICATE REQUEST-----
MIIDBjCCAe4CAQAwaDELMAkGA1UEBhMCQVUxDDAKBgNVBAgTA05TVzEPMA0GA1UE
BxMGU3lkbmV5MQwwCgYDVQQKEwNZdW0xDjAMBgNVBAsTBVl1bUlTMRwwGgYDVQQD
ExN0ZXN0LmF1LmludC50Z3IubmV0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
CgKCAQEAygZvKhfs0mw4tModevTxOIz7eYYM+1axNv8FqoNyKr7xtqSbOMiNzf8R3rZ
4cTcu5nv7oC7GHPMhnF7AdsO4XexwnKfnCkofECGkO6O4oTmRfUPLa38nV1+mytB
lrQAl272jQdM9LSxTYW0OR9qO4mjAH1tvLF3IcC1OKOh6UNubdRFfE7dEXWnk+SF
M8tgl0t3SFsRxrZL3vkgL+/EmvdOKXeoIey/7UMNeWRcwTkS1mw30HjvitJdQGZi
gYJ6ldXrrITVKe9QXvVTxSl9NfzPHYp4yf/ZvAJQmGLZ16aQo0PBeEfjkgkrcY5j
MnVI2Q8yC+W9Bg==
-----END CERTIFICATE REQUEST-----&CertAttrib=CertificateTemplate:*WebServer
UserAgent:Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0)
like Gecko &FriendlyType=Saved-Request Certificate (7/7/2015, 3:46:39
PM)&ThumbPrint=&TargetStoreFlags=0&SaveCert=yes
重新编码:(URLEncode1, URLEncode2, URLEncode3):
Mode%3Dnewreq%26CertRequest%3D-----BEGIN+CERTIFICATE+REQUEST-----+MIIDBjCCAe4CAQAwaDELMAkGA1UEBhMCQVUxDDAKBgNVBAgTA05TVzEPMA0GA1UE+BxMGU3lkbmV5MQwwCgYDVQQKEwNZdW0xDjAMBgNVBAsTBVl1bUlTMRwwGgYDVQQD+ExN0ZXN0LmF1LmludC50Z3IubmV0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB+CgKCAQEAygZvKhfs0mw4tModevTxOIz7eYYM%2B1axNv8FqoNyKr7xtqSbOMiNzf8R3rZ+4cTcu5nv7oC7GHPMhnF7AdsO4XexwnKfnCkofECGkO6O4oTmRfUPLa38nV1%2BmytB+lrQAl272jQdM9LSxTYW0OR9qO4mjAH1tvLF3IcC1OKOh6UNubdRFfE7dEXWnk%2BSF+M8tgl0t3SFsRxrZL3vkgL%2B%2FEmvdOKXeoIey%2F7UMNeWRcwTkS1mw30HjvitJdQGZi+gYJ6ldXrrITVKe9QXvVTxSl9NfzPHYp4yf%2FZvAJQmGLZ16aQo0PBeEfjkgkrcY5j+MnVI2Q8yC%2BW9Bg%3D%3D+-----END+CERTIFICATE+REQUEST-----%26CertAttrib%3DCertificateTemplate%3A%2AWebServer+UserAgent%3AMozilla%2F5.0+%28Windows+NT+6.3%3B+WOW64%3B+Trident%2F7.0%3B+rv%3A11.0%29+like+Gecko+%26FriendlyType%3DSaved-Request+Certificate+%287%2F7%2F2015%2C+3%3A46%3A39+PM%29%26ThumbPrint%3D%26TargetStoreFlags%3D0%26SaveCert%3Dyes
上面链接的三个网站(重新编码)都无法正确重新编码。 棘手的部分是“=”和“&”不应该被编码。
URL Encode Simple:
CR LF %0D%0A (Not %)
Space + (Not %20)
- - (Not %2D)
& & (Not %26)
= = (Not %3D)
+ (in CSR) %2B
\ (in CSR) %2F
( %28
) %29
我可以具体地使用sed这个例子,但我想知道是否有办法知道服务器期望的编码,并编码在正确的字符集中 自动 。这可能吗?
这是 Windows (CYGWIN) 上的 bash 脚本:
#!/bin/bash
#############################################################################################
# AUTHOR: FlORIAN BIDABE #
# #
# VERSION 2.0 RELEASE DATE February 07, 2018 #
# This script helps you with generating SSL material from an internal Micorosft CA #
# 1) Define your variables and CA Bundle in this script (between < and >) #
# 2) Run the script #
# #
# Process: #
# 1- Generate or import CSR #
# 2- Submit CSR and specify additional Subject Alternate Name (SAN) #
# 3- Collect certificate from your CA (Certificate Authority) ==> MANUAL #
# 4- Generate SSL material and format #
# #
# #
# Tested on: #
# Certificate Authority: Windows Server 2008 R2 / 2012 #
# Client: Windows 8.1 and Windows 10 with cygwin (cURL, OpenSSL, clip) #
#############################################################################################
#_____________________________________________________________________________________________
######################################## Variables ########################################
# Internal Env Settings
MSCA='server.domain.tld' # Internal Microsoft Certification Authority FQDN
CertTplt='WebServer' # Internal Cert Template Name
UA='Mozilla%2F5.0+%28Windows+NT+6.3%3B+WOW64%3B+Trident%2F7.0%3B+rv%3A11.0%29+like+Gecko'
Domain='localdomain' # Used for signing both hostname and FQDN
Username=""$Domain"\userid" # Required for certificate submission
#Password='WH4t3v3r' # Can be commented to be interactive
# Email Settings (Unauthenticated in my case)
mailserver="mailserver.com" # Mailserver FQDN
mailport=25 # Might need SSL if 465, 587
to="ServiceDesk@company.com"
cc="who.ever@company.com"
bcc="yourself@company.com,fortrackingpurpose@company.com"
MailTemplate="
Hello,
Please create and assign a ticket to track this certificate request from our market.
The Request ID has been attached in the email (HTTP Response)
Date: `date "+%Y-%m-%d %H:%M"`
Issuer: "$Username"
Information Systems
Phone number
Company Pty Ltd
Address and contact details"
# SaveIn=~/Desktop/Certs
SaveIn=~/Certificates/NewRequests # Save the file in Team's OneDrive folder mapped with ln using cygwin
FileMgr=explorer # File Manager
# OpenSSL CFG settings for CSR (Code Signing Request) submission
Country='AU'
State='NSW'
City='Sydney'
Company='Company'
UrOrg='Information Systems'
# Internal Base64 Root and Intermediate CAs (Used for creating PEM and PKCS12 bundles)
IntRoot=`echo '
-----BEGIN CERTIFICATE-----
<Intermediate>
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
<Root>
-----END CERTIFICATE-----'`
#_____________________________________________________________________________________________
######################################## Requirements ########################################
# OpenSSL
type openssl > /dev/null 2>&1 || {
echo "Cannot find OpensSSL, it is required to generate certificates. Aborting..." 1>&2
exit 1
}
# cURL
type curl > /dev/null 2>&1 || {
echo "Cannot find cURL, it is required to submit certificates. Aborting..." 1>&2
exit 1
}
#_____________________________________________________________________________________________
######################################## Optional ############################################
# Clip
type clip > /dev/null 2>&1 || {
echo -e "Cannot find clip ! it is required to save the CSR into your clipboard.\n Attempting to install it in System32..." 1>&2
cd 'C:\Windows\system32'; curl -L -O "https://www.dropbox.com/s/cvkxeak0j0wtjj0/clip.exe"
}
# GNU Email
type email > /dev/null 2>&1 || {
echo -e "Cannot find GNU email ! it is required to send an email to notify a security administrator and issue the certificate." 1>&2
}
# Internet Explorer
if [ -f '/cygdrive/c/Program\ Files/Internet\ Explorer/iexplore.exe' ]; then iexplore='/cygdrive/c/Program\ Files/Internet\ Explorer/iexplore.exe'
else iexplore=$(sed 's| |\ |g' <<< "$(find /cygdrive/ -name "iexplore.exe" -exec sh -c 'printf "%s\n" ""; kill "$PPID"' bash {} \;)")
fi
#_____________________________________________________________________________________________
######################################## Functions ########################################
gencsr() {
# Generate Config File (CFG) for Code Signing Request (CSR)
echo "`date "+%Y-%m-%d %H:%M:%S"` - User Option: 1) Generate CSR and Private Key" >> $LOGS
echo "`date "+%Y-%m-%d %H:%M:%S"` - Parsing Config File (CFG)" >> $LOGS
# Set additional SAN (for CFG)
local n=1 #Enter Loop
local SAN
SAN="subjectAltName = DNS:"$Hostname", DNS: "$Hostname.$Domain""
while (( n > 0 && n < 4 )); do
echo -e "\n\n\nDo you want to set an additional Subject Alternate Name (Config File) ? (No)"
echo -e "Current SAN:\n"$SAN""
echo -e "Select your choice and press [ENTER]\n\t[1] Add an IP address\n\t[2] Add an hostname\n\t[3] Reset SAN to default\n\t[*] Continue"
read -p "Option number : " n
case $n in
1) # Add Extra IP for SAN
while [[ -z ${IP+x} || $? != 0 ]]; do
read -p "What is the server's IP address: " IP
[[ "$IP" =~ ^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]).){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$ ]]
if [ $? != 0 ]; then echo "This IP address ("$IP") does not look quite right! Please try again..."; fi
[[ "$IP" =~ ^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]).){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$ ]]
done
SAN+=", IP:"$IP", DNS:"$IP""; unset IP
;;
2) # Add extra DNS name to SAN
while [[ -z ${extraSAN+x} || $? != 0 ]]; do
read -p "Specify a Fully Qualified Domain Name for the extra SAN : " extraSAN
[[ "$extraSAN" =~ ^[A-Za-z0-9.-]+$ ]]
if [ $? != 0 ]; then echo "This syntax is incorrect! Please try again..."; fi
[[ "$extraSAN" =~ ^[A-Za-z0-9.-]+$ ]]
done
SAN+=", DNS:"$extraSAN""; unset extraSAN
;;
3) SAN="subjectAltName = DNS:"$Hostname", DNS:"$Hostname.$Domain"" ;;
*) n=4 ;; #Quit loop
esac
done
echo "`date "+%Y-%m-%d %H:%M:%S"` - Subject Alternate Name (CFG): "$SAN"" >> $LOGS
echo "
[ req ]
default_md = sha512
default_bits = 2048
default_keyfile = "$Hostname"_pk8.key
distinguished_name = req_distinguished_name
encrypt_key = no
prompt = no
string_mask = nombstr
req_extensions = v3_req
input_password = password
output_password = password
[ v3_req ]
basicConstraints = CA:false
keyUsage = digitalSignature, keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth, clientAuth
"$SAN"
[ req_distinguished_name ]
countryName = "$Country"
stateOrProvinceName = "$State"
localityName = "$City"
0.organizationName = "$Company"
organizationalUnitName = "$UrOrg"
commonName = "$Hostname.$Domain"" > "$Hostname".cfg
echo "`date "+%Y-%m-%d %H:%M:%S"` - Config File (CFG) parsed ! Located at `pwd`/"$Hostname".cfg" >> $LOGS
# Generate CSR and private key (PKCS8) & convert Private Key (PKCS8 to PKCS1)
echo -e "\n\nGenerating Code Signing Request (CSR) and Private Key (PKCS#8)..."
echo "`date "+%Y-%m-%d %H:%M:%S"` - Generating Code Signing Request (CSR) and Private Key (PKCS#8): "$Hostname".csr and "$Hostname"_pk8.key" >> $LOGS
openssl req -out "$Hostname".csr -new -nodes -config "$Hostname".cfg > /dev/null 2>&1
echo "Generating private key (PKCS#1)..."
echo "`date "+%Y-%m-%d %H:%M:%S"` - Generating Private Key (PKCS#1): "$Hostname"_pk1.key" >> $LOGS
openssl rsa -in "$Hostname"_pk8.key -out "$Hostname"_pk1.key > /dev/null 2>&1
if [ $? != 0 ]; then
echo "An error has occured ! Exiting..., Please consult the logs"
echo "`date "+%Y-%m-%d %H:%M:%S"` - Error on generating CSR or Private Keys" >> $LOGS
exit 1
fi
}
importcsr() {
# Importing Code Signing Request (CSR)
echo "`date "+%Y-%m-%d %H:%M:%S"` - User Option: 2) Import CSR" >> $LOGS
local n
printf "3c"
echo -e "This function automates IIS7 certificate generation for "$Company $UrOrg"
\tServer name:\t"$Hostname"\n\tFQDN:\t\t"$Hostname"."$Domain"\n"
echo "Importing Code Signing Request..."
#Verify CSR
# If CSR is not Base 64
openssl req -text -noout -verify -in *.csr > /dev/null 2>&1
while [ $? != 0 ]; do
# Check if there are multiple csr files
while [ $(find -name "*.csr" | wc -l) != 1 ]; do
echo -e "\nError, $(find -name "*.csr" | wc -l) CSR(s) found ! One CSR is required..."
echo "Please import your CSR in "$SaveIn" and make sure the extension is *.csr"
echo "`date "+%Y-%m-%d %H:%M:%S"` - WARNING: There should be one CSR only in "$SaveIn"" >> $LOGS
$FileMgr . 2> /dev/null
read -p "Press any key to continue...";
done
openssl req -text -noout -verify -inform DER -in *.csr > /dev/null 2>&1
if [ $? == 0 ]; then
echo -e "\n\nThis Code Signing Request is not a Base64 request !\nConverting DER request to Base64... Success !"
mv *.csr "$Hostname".dcsr
openssl req -out "$Hostname".csr -outform PEM -inform DER -in *.dcsr
echo "`date "+%Y-%m-%d %H:%M:%S"` - DER CSR detected, converting to Base64... Success !" >> $LOGS
echo "`date "+%Y-%m-%d %H:%M:%S"` - DER CSR: "$Hostname".dcsr\tBase64 CSR: "$Hostname".csr" >> $LOGS
else
openssl req -text -noout -verify -in *.csr > /dev/null 2>&1
if [ $? != 0 ]; then
echo -e "Your CSR file is not valid or is corrupted!\nPlease import your CSR in "$SaveIn"..."
echo "`date "+%Y-%m-%d %H:%M:%S"` - ERROR: This CSR is invalid, it is neither a DER or Base64 CSR" >> $LOGS
$FileMgr . 2> /dev/null
read -p "Press any key to continue..."; fi
fi
openssl req -text -noout -verify -in *.csr > /dev/null 2>&1
done
# Optional: Converting a Base64 CSR to DER
if [ ! -f *.dcsr ]; then
openssl req -outform DER -inform PEM -in *.csr -out "$Hostname".dcsr > /dev/null 2>&1
if [ $? == 0 ]; then
echo "`date "+%Y-%m-%d %H:%M:%S"` - Base64 CSR detected, converting to DER... Success !" >> $LOGS
echo "`date "+%Y-%m-%d %H:%M:%S"` - DER CSR: "$Hostname".dcsr\tBase64 CSR: "$Hostname".csr" >> $LOGS
fi
fi
}
urlencode() {
local data
if [[ $# != 1 ]]; then return 1; fi
data="$(curl -s -o /dev/null -w %{url_effective} --get --data-urlencode "" "")"
if [[ $? != 3 ]]; then return 2; fi
echo "${data##/?}"; return 0
}
getcert() {
######################### 3- Get Certificate ########################
echo -e "\n\n`date "+%Y-%m-%d %H:%M:%S"` - Step 3: Getting the Certifiate" >> $LOGS
printf "3c"
echo -e "This function automates IIS7 certificate generation for "$Company $UrOrg"
\tServer name:\t"$Hostname"\n\tFQDN:\t\t"$Hostname"."$Domain"\n"
echo -e "Open \"Certificate Authority\" in a Management Console (MMC) and connect to "$MSCA"\nVerify that your certificate request is in "Pending Requests".\nIssue the Certificate (Right Click, All Tasks, Issue)\nNavigate to "Issue Certificates", order by Request ID (Descending) and export it (Open / Details / Copy To File) 'Base-64 Encoded X.509' to "$SaveIn".\nThe file must have a *.cer extension\n"
read -p "Press any keys when the certificate (*.cer) has been place in "$SaveIn""
#Verify Certificate
openssl x509 -text -noout -in "$Hostname".cer > /dev/null 2>&1
while [ $? != 0 ]; do
# Verify that there is only one certificate
while [ $(find -name "*.cer" | wc -l) == 0 ]; do
echo "Please import certificate (*.cer) in "$SaveIn""
if [ -z ${Manual+x} ]; then $FileMgr . 2> /dev/null
else
#If the certificate has been uploaded using a browser, it can be retrieved using the browser
if [ -z ${iexplore+x} ]; then echo "Open "https://"$MSCA"/certsrv/certckpn.asp""
else eval $iexplore "https://"$MSCA"/certsrv/certckpn.asp"; fi
fi
read -p "Press any key to continue..."; done
while [ $(find -name "*.cer" | wc -l) != 1 ]; do
echo "Error, $(find -name "*.cer" | wc -l) certificates found in "$SaveIn"! Please clean it up !"
$FileMgr . 2> /dev/null
read -p "Press any key to continue..."
done
# Verify Certificate Integrity and format
mv *.cer "$Hostname".cer
echo -e "`date "+%Y-%m-%d %H:%M:%S"` - Certificate found at `pwd`/"$Hostname".cer" >> $LOGS
openssl x509 -text -noout -in *.cer > /dev/null 2>&1
if [ $? != 0 ]; then
openssl x509 -inform der -text -noout -in *.cer > /dev/null 2>&1 # Test if DER
if [ $? == 0 ]; then # Convert DER to Base64
mv *.cer "$Hostname".der
openssl x509 -inform der -in "$Hostname".der -out "$Hostname".cer > /dev/null 2>&1
echo "`date "+%Y-%m-%d %H:%M:%S"` - DER certificate detected, converting to Base64... Success !" >> $LOGS
echo "`date "+%Y-%m-%d %H:%M:%S"` - DER certificate: "$Hostname".der\tBase64 certificate: "$Hostname".cer" >> $LOGS
else
echo -e "This certificate is invalid or corrupted!\nPlease import it again in "$SaveIn"..."
echo "`date "+%Y-%m-%d %H:%M:%S"` - ERROR: The certificate is invalid, it is neither a DER or Base64 certificate" >> $LOGS
read -p "Press any key to continue..."
fi
openssl x509 -text -noout -in *.cer > /dev/null 2>&1
fi
done
# Optional: Converting a Base64 CSR to DER
if [ ! -f *.der ]; then
openssl x509 -outform der -in "$Hostname".cer -out "$Hostname".der > /dev/null 2>&1
if [ $? == 0 ]; then
echo "`date "+%Y-%m-%d %H:%M:%S"` - Base64 Certificate detected, converting to DER... Success !" >> $LOGS
echo "`date "+%Y-%m-%d %H:%M:%S"` - DER Certificate: "$Hostname".dcsr\tBase64 Certificate: "$Hostname".csr" >> $LOGS
fi
fi
###################### 4- Generating SSL material #########################
# Creating PEM certificate chain
echo -e "`date "+%Y-%m-%d %H:%M:%S"` - Step 4 (Final): Generating SSL material" >> $LOGS
if [ -f ""$Hostname"_pk1.key" ]; then
cat "$Hostname"_pk1.key > ""$Hostname".pem"
cat *.cer >> ""$Hostname".pem"
echo -e "`date "+%Y-%m-%d %H:%M:%S"` - A PEM has been generated containing the Private Key and entire certificate chain: Public Key for "$Hostname" and CA Bundle (intermediate and root certificates) " >> $LOGS
else
cat *.cer > ""$Hostname".pem"
echo -e "`date "+%Y-%m-%d %H:%M:%S"` - A PEM has been generated containing the entire certificate chain: Public Key for "$Hostname" and CA Bundle (intermediate and root certificates)" >> $LOGS
echo -e "`date "+%Y-%m-%d %H:%M:%S"` - As the CSR was imported, no private key can be included in the PEM container" >> $LOGS
fi
echo "$IntRoot" >> ""$Hostname".pem"
sed -i '/^$/d' "$Hostname".pem"" # Delete empty lines
# Converting PEM certificate chain to PKCS#12 (.pfx)"
cat *.pfx 2> /dev/null #Enter Loop
while [ $? != 0 ]; do
if [ -f "$Hostname"_pk1.key ]; then openssl pkcs12 -export -out ""$Hostname".pfx" -in ""$Hostname".pem"
else openssl pkcs12 -export -nokeys -out ""$Hostname".pfx" -in ""$Hostname".pem"
fi
done
echo -e "`date "+%Y-%m-%d %H:%M:%S"` - A PKCS12 (.pfx, .p12) has been generated from the PEM" >> $LOGS
echo -e "`date "+%Y-%m-%d %H:%M:%S"` - Ending gracefully :)" >> $LOGS
mv ../"$Hostname" ../../INTERNAL/
cd ../../INTERNAL/"$Hostname"
$FileMgr . 2> /dev/null
exit 0
}
#_____________________________________________________________________________________________
######################################## GUI ########################################
printf "3c"
echo -e "This function automates IIS7 certificate generation for "$Company $UrOrg""
# Set Hostname and IP address
Hostname=""; [[ "$Hostname" =~ ^[-A-Za-z0-9]+$ ]]
while [ $? != 0 ]; do
read -p "Specify the server hostname (Not FQDN !): " Hostname
[[ "$Hostname" =~ ^[-A-Za-z0-9]+$ ]]
if [ $? != 0 ]; then echo "This hostname syntax is incorrect, try again !"; fi
[[ "$Hostname" =~ ^[-A-Za-z0-9]+$ ]]
done
LOGS=""$Hostname".logs"
# Set destination folder for SSL material
SaveIn+="/"$Hostname"";
if [ -d "$SaveIn" ]; then
echo "A folder named "$Hostname" already exists, Start over (delete existing materials) or quit ?"
echo -e "Select your choice and press [ENTER]\n\t[1] Start Over (Delete existing content)\n\t[2] Resume (Certificate Generation)\n\t[*] Quit"
read -p "Option number : " n
case $n in
1) rm -R "$SaveIn" > /dev/null 2>&1; mkdir -p "$SaveIn" > /dev/null 2>&1; cd "$SaveIn" ;;
2) cd "$SaveIn"; getcert "$@" ;;
*) echo "Aborting..."; exit 0 ;;
esac
else mkdir -p "$SaveIn"; cd "$SaveIn"
fi
###LOGGING GUI###
echo "`date "+%Y-%m-%d %H:%M:%S"` - Starting... Path: `pwd`" > $LOGS
echo "`date "+%Y-%m-%d %H:%M:%S"` - OpenSSL Version: `openssl version`" >> $LOGS
echo "`date "+%Y-%m-%d %H:%M:%S"` - cURL Version: `head -n 1 <(curl --version)`" >> $LOGS
echo "`date "+%Y-%m-%d %H:%M:%S"` - Server name: "$Hostname" FQDN: "$Hostname"."$Domain"" >> $LOGS
######################### 1- Get CSR ###############################
echo -e "\n\n`date "+%Y-%m-%d %H:%M:%S"` - Step 1: Code Signing Request" >> $LOGS
printf "3c"
echo -e "This function automates IIS7 certificate generation for "$Company $UrOrg"
\tServer name:\t"$Hostname"\n\tFQDN:\t\t"$Hostname"."$Domain"\n"
echo -e "\nCode Signing Request (CSR):\n\tYou can generate a CSR and Private key or import a CSR (generated by an appliance and downloaded by you).
\tPlease note that importing a CSR means that the private key remains on the appliance or vendor's site.
\tSelect your choice and press [ENTER]\n\t[1] Generate CSR and Private Key\n\t[2] Import CSR\n\t[*] Quit"
read -p "Option number : " n
case $n in
1) gencsr "$@" ;;
2) importcsr "$@" ;;
*) echo "`date "+%Y-%m-%d %H:%M:%S"` - User Option: Quit" >> $LOGS; echo "Aborting..."; exit 0 ;;
esac
######################### 2- Submit CSR ############################
echo -e "\n\n`date "+%Y-%m-%d %H:%M:%S"` - Step 2: Submitting CSR" >> $LOGS
# Capture Attempt: Session ID cookie
echo "`date "+%Y-%m-%d %H:%M:%S"` - Capturing Session ID cookie from "$MSCA"" >> $LOGS
echo 'Capturing ASP Session ID (Cookie)...'
if [ -z "$Password" ]; then echo "What is the password for $Username ?: "; read -s Password; fi
RE=': ([^;]*);' #Regex to capture ASP Session ID from cookie string
while read l; do [[ $l =~ $RE ]] && AspSession="${BASH_REMATCH[1]}"; done <<<"$(grep "Cookie" <<< "$(curl --silent -Iku "$Username":"$Password" --ntlm https://"$MSCA"/certsrv/certrqxt.asp)")"
# If fail capturing cookie ==> Manual (Browser-Mode)
if [ -z "$AspSession" ]; then
echo "`date "+%Y-%m-%d %H:%M:%S"` - ERROR: Cannot capture Session ID cookie, failover to browser-mode..." >> $LOGS
echo "WARNING: Cannot capture Session ID cookie for "$MSCA", failover to browser-mode...\nPlease verify your credentials to connect to $MSCA\n\n"
echo "Paste CSR directly in internal CA web interface"
echo -e "\tConfirm the Subject Alternate Name field before submission !\n\tNote that the CSR may already include SAN(s) !
Current Subject: `openssl req -in *.csr -noout -text | grep "Subject:"`
Current SAN: `openssl req -in *.csr -noout -text | grep "DNS:"`"
clip <<< "$(cat *.csr 2> /dev/null)" ; Manual=1
echo -e "Please upload your Code Signing Request to your Internal Certificate Authority ("$MSCA") :"
if [ -z ${iexplore+x} ]; then
echo "Open "https://"$MSCA"/certsrv/certrqxt.asp" in a browser"
else
eval $iexplore "https://"$MSCA"/certsrv/certrqxt.asp" &
echo "Press any key to continue..." ; read
fi
fi
# If Session ID cookie sucessfully captured ==> Automatic (cURL-Mode)
if [ -z ${Manual+x} ]; then
echo "ASP cookie captured !"
# Set additional SAN (for cURL)
echo -e "\n\nConfirm the Subject Alternate Name before submission:
Current Common Name: `openssl req -in *.csr -noout -text | grep "Subject:"`
Current SAN: `openssl req -in *.csr -noout -text | grep "DNS:"`"
echo -e "\nDo you want to add a Subject Alternate Name (No) ?\nSelect your choice and press [ENTER]\n\t[1] Yes\n\t[*] No\n"
read -p "Option number : " n
case $n in
1) unset n; n=1 #Enter Loop
unset SAN; SAN="san%3Adns%3D"$Hostname"%26dns%3D"$Hostname.$Domain""
while (( n > 0 && n < 4 )); do
echo -e "\n\n\nDo you want to set an additional Subject Alternate Name ? (No)"
echo -e "Current SAN (URL Encoded): "$SAN""
echo -e "Select your choice and press [ENTER]\n\t[1] Add an IP address\n\t[2] Add an hostname\n\t[3] Reset SAN to default\n\t[*] Continue"
read -p "Option number : " n
case $n in
1) # Add Extra IP for SAN
while [[ -z ${IP+x} || $? != 0 ]]; do
read -p "What is the server's IP address: " IP
[[ "$IP" =~ ^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]).){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$ ]]
if [ $? != 0 ]; then echo "This IP address ("$IP") does not look quite right! Please try again..."; fi
[[ "$IP" =~ ^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]).){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$ ]]
done
SAN+="%26dns%3D"$IP""; unset IP
;;
2) # Add extra DNS name to SAN
while [[ -z ${extraSAN+x} || $? != 0 ]]; do
read -p "Specify a Fully Qualified Domain Name (FQDN) for the extra SAN: " extraSAN
[[ "$extraSAN" =~ ^[A-Za-z0-9.-]+$ ]]
if [ $? != 0 ]; then echo "This syntax is incorrect! Please try again..."; fi
[[ "$extraSAN" =~ ^[A-Za-z0-9.-]+$ ]]
done
SAN+="%26dns%3D"$extraSAN""; unset extraSAN
;;
3) SAN="san%3Adns%3D"$Hostname"%26dns%3D"$Hostname.$Domain"" ;;
*) n=4 ; SAN+='%0D%0A' ;; #Quit loop
esac
done
;;
*) ;;
esac
CertFormat=$(sed 's| |+|g' <<< $(sed 's|+|%2B|g' <<< $(sed 's|/|%2F|g' <<< $(sed ':a;N;$!ba;s/\n/%0D%0A/g' *.csr))))
Date=$(sed 's|%20|+|g' <<< $(urlencode "`date '+%m/%d/%Y,%r'`"))
cURLData="Mode=newreq&CertRequest="$CertFormat"&CertAttrib="$SAN"CertificateTemplate%3A"$CertTplt"%0D%0AUserAgent="$UA"%0D%0A&FriendlyType=Saved-Request+Certificate+%28"$Date"%29&ThumbPrint=&TargetStoreFlags=0&SaveCert=yes"
echo "`date "+%Y-%m-%d %H:%M:%S"` - Generating and encoding cURL POST data..." >> $LOGS
echo -e "Injecting crafted POST request to Internal CA using cURL and NTLM authentication...\n"
echo "`date "+%Y-%m-%d %H:%M:%S"` - Injecting crafted POST request to Internal CA using cURL and NTLM authentication..." >> $LOGS
InjectCmd="curl --silent -i -ku '$Username':'$Password' --ntlm '"https://"$MSCA"/certsrv/certfnsh.asp"' \
-H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' \
-H 'Accept-Encoding: gzip, deflate' \
-H 'Accept-Language: en-US,en;q=0.5' \
-H 'Connection: keep-alive' -H 'Cookie: "$AspSession"' \
-H 'Host: "$MSCA"' \
-H 'Referer: https://"$MSCA"/certsrv/certrqxt.asp' \
-H 'User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko' \
-H 'Content-Type: application/x-www-form-urlencoded' --data '"$cURLData"'"
InjectCmdLog=`echo $InjectCmd | sed "s|"$Password"|<password>|g"`
echo "`date "+%Y-%m-%d %H:%M:%S"` - Command: "$InjectCmdLog"" >> $LOGS
echo "`date "+%Y-%m-%d %H:%M:%S"` - BEGIN HTTP REPLY: Consult "$Hostname".html" >> $LOGS
eval "$InjectCmd" &> "$Hostname.html"
echo "`date "+%Y-%m-%d %H:%M:%S"` - END HTTP REPLY" >> $LOGS
if [ $? != 0 ] || grep -q 'Access Denied' "$Hostname.html" || grep -q 'Denied by Policy Module' "$Hostname.html"; then
echo -e "Injection seems to have gone wrong! Please verify if the request is missing in the Certificate Authority Snap-In on "$MSCA""
echo -e "Consult Log file for analysis of the cURL query: it might be malformed!"
echo -e "Log file location: `pwd`/"$LOGS""
echo "`date "+%Y-%m-%d %H:%M:%S"` - Injection has failed !" >> $LOGS
exit 1
fi
fi
email "$to" -cc "$cc" -bcc "$bcc" -a "$Hostname".html -s "Certificate Request: Please issue $Hostname.$Domain certificate" -r $mailserver -p $mailport <<< "$MailTemplate"
echo "An email has been sent to the US (You are in CC) ! Once approved, please connect to "$MSCA" to retrieve your certificate using the Certificate Authority via mmc.exe"
echo "Once retrieved, open again this utility, enter the same hostname ("$Hostname") and resume operations: this will generates cryptographic material bundles (PEM, #PKCS12... etc.)"
echo "Please take notes of password you set to access the private key on the PKCS12 material"
我在 bash 上解决了 linux 和 curl:
#!/bin/sh
# tested on SUSE Linux 12 SP1
# - CN Object name
# - username
# - password
MSCA='HOSTNAME' # Internal Microsoft Certification Authority
Username=
Password=
function show_usage()
{
echo "Scrip for retrive certificate from MS SubCA"
echo "Usage: [=10=] <CN> [domain\\username] [password]"
echo " "
echo "Example: [=10=] example.com workgroup\\foo bar"
exit 0
}
if [ -z "" ]
then
show_usage
exit 0
fi
if [ -z "" ]
then
Username="workgroup\foo"
Password="bar"
fi
echo -e "\e[32m1. Generate private key...\e[0m"
openssl req -new -nodes -out .pem -keyout .key -subj "/C=RU/ST=State/L=City/O=Org/CN=/emailAddress=postmaster@example.com"
CERT=`cat .pem | tr -d '\n\r'`
DATA="Mode=newreq&CertRequest=${CERT}&C&TargetStoreFlags=0&SaveCert=yes"
CERT=`echo ${CERT} | sed 's/+/%2B/g'`
CERT=`echo ${CERT} | tr -s ' ' '+'`
CERTATTRIB="CertificateTemplate:Server%0D%0A"
echo -e "\e[32m2. Request cert...\e[0m"
OUTPUTLINK=`curl -k -u "${Username}":${Password} --ntlm \
"https://${MSCA}/certsrv/certfnsh.asp" \
-H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' \
-H 'Accept-Encoding: gzip, deflate' \
-H 'Accept-Language: en-US,en;q=0.5' \
-H 'Connection: keep-alive' \
-H "Host: ${MSCA}" \
-H "Referer: https://${MSCA}/certsrv/certrqxt.asp" \
-H 'User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko' \
-H 'Content-Type: application/x-www-form-urlencoded' \
--data "Mode=newreq&CertRequest=${CERT}&CertAttrib=${CERTATTRIB}&TargetStoreFlags=0&SaveCert=yes&ThumbPrint=" | grep -A 1 'function handleGetCert() {' | tail -n 1 | cut -d '"' -f 2`
CERTLINK="https://${MSCA}/certsrv/${OUTPUTLINK}"
echo -e "\e[32m3. Retrive cert: $CERTLINK\e[0m"
curl -k -u "${Username}":${Password} --ntlm $CERTLINK \
-H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' \
-H 'Accept-Encoding: gzip, deflate' \
-H 'Accept-Language: en-US,en;q=0.5' \
-H 'Connection: keep-alive' \
-H "Host: ${MSCA}" \
-H "Referer: https://${MSCA}/certsrv/certrqxt.asp" \
-H 'User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko' \
-H 'Content-Type: application/x-www-form-urlencoded' > .crt
echo -e "\e[32m4. Verifying cert for \e[0m"
openssl verify -verbose .crt
if [ "0" -eq "$?" ] ;
then
echo -e "\e[32mWell done. Have a nice day.\e[0m"
exit 0
else
echo -e "\e[31;47mError code: $?. Stopping.\e[0m"
exit 1
fi
这是我从论坛帖子(包括这篇帖子)中借用的部分以及我自己完成的一些内容的组合。它有一些东西可以容纳 Aruba Instant AP 和它接受的证书格式。专为满足我实验室的需求而量身定制。
这里的答案很好,@SkazochNik J 提供了最后一块(自动提交 csr 并检索证书)。 @SkazochNik 如果你碰巧看到这个,我要找的最后一件事就是通过 curl/bash 从 CA 中提取 CA 证书。如果你碰巧知道那里的格式,那就太棒了......
如果这有用,我构建的(到目前为止):
#!/usr/bin/env bash
MSCA='dc1.myDomain.com' # Internal Microsoft Certification Authority
Username=<domain\user>
Password=<pass>
echo "-- Certificate csr and key generator --"
echo "-- all certificates use myDomain.com domain --"
echo " "
echo "Is this certificate for a wireless controller/vc [y/n]"
read _isWlan
echo "provide all hostnames to be used as the CN first then additional SAN values (only the hostname)"
read _host1 _host2 _host3 _host4 _host5
echo "provide all IP addresses desired as SAN values"
read _ip1 _ip2 _ip3 _ip4 _ip5
if [ ${_isWlan,,} == 'y' ] || [ ${_isWlan,,} == 'yes' ]; then _isWlan=true; fi
if [ -z "$_host2" ]; then _dns2=false; else _dns2=true; fi
if [ -z "$_host3" ]; then _dns3=false; else _dns3=true; fi
if [ -z "$_host4" ]; then _dns4=false; else _dns4=true; fi
if [ -z "$_host5" ]; then _dns5=false; else _dns5=true; fi
if [ -z "$_ip2" ]; then _ip2in=false; else _ip2in=true; fi
if [ -z "$_ip3" ]; then _ip3in=false; else _ip3in=true; fi
if [ -z "$_ip4" ]; then _ip4in=false; else _ip4in=true; fi
if [ -z "$_ip5" ]; then _ip5in=false; else _ip5in=true; fi
echo "[req]" > $_host1.cnf
echo "default_bits = 2048" >> $_host1.cnf
echo "prompt = no" >> $_host1.cnf
echo "default_md = sha256" >> $_host1.cnf
echo "req_extensions = req_ext" >> $_host1.cnf
echo "distinguished_name = dn" >> $_host1.cnf
echo " " >> $_host1.cnf
echo "[ dn ]" >> $_host1.cnf
echo "C=US" >> $_host1.cnf
echo "ST=Indiana" >> $_host1.cnf
echo "L=Noblesville" >> $_host1.cnf
echo "O=WadeLab" >> $_host1.cnf
echo "OU=Engineering" >> $_host1.cnf
echo "emailAddress=wade1@hpe.com" >> $_host1.cnf
if $_isWlan; then
echo "CN = securelogin.myDomain.com" >> $_host1.cnf
else
echo "CN = "$_host1".myDomain.com" >> $_host1.cnf
fi
echo " " >> $_host1.cnf
echo "[ req_ext ]" >> $_host1.cnf
echo "subjectAltName = @alt_names" >> $_host1.cnf
echo " " >> $_host1.cnf
echo "[ alt_names ]" >> $_host1.cnf
# it would be prettier to populate an array from the input and loop through them, but it would take me longer
# to refresh my knowledge for the bash way to do that then it did to copy paste all this
if $_isWlan; then
echo "DNS.1 = securelogin.myDomain.com" >> $_host1.cnf
echo "DNS.2 = "$_host1".myDomain.com" >> $_host1.cnf
echo "DNS.3 = "$_host1 >> $_host1.cnf
if $_dns2; then
echo "DNS.4 = "$_host2".myDomain.com" >> $_host1.cnf
fi
if $_dns3; then
echo "DNS.5 = "$_host3".myDomain.com" >> $_host1.cnf
fi
if $_dns4; then
echo "DNS.6 = "$_host4".myDomain.com" >> $_host1.cnf
fi
if $_dns5; then
echo "DNS.7 = "$_host5".myDomain.com" >> $_host1.cnf
fi
else
echo "DNS.1 = "$_host1".myDomain.com" >> $_host1.cnf
echo "DNS.2 = "$_host1 >> $_host1.cnf
if $_dns2; then
echo "DNS.3 = "$_host2".myDomain.com" >> $_host1.cnf
fi
if $_dns3; then
echo "DNS.4 = "$_host3".myDomain.com" >> $_host1.cnf
fi
if $_dns4; then
echo "DNS.5 = "$_host4".myDomain.com" >> $_host1.cnf
fi
if $_dns5; then
echo "DNS.6 = "$_host5".myDomain.com" >> $_host1.cnf
fi
fi
echo "IP.1 = "$_ip1 >> $_host1.cnf
if $_ip2in; then
echo "IP.2 = "$_ip2 >> $_host1.cnf
fi
if $_ip3in; then
echo "IP.3 = "$_ip3 >> $_host1.cnf
fi
if $_ip4in; then
echo "IP.4 = "$_ip4 >> $_host1.cnf
fi
if $_ip5in; then
echo "IP.5 = "$_ip5 >> $_host1.cnf
fi
echo
echo "1. Creating Certificate Request..."
openssl req -nodes -newkey rsa:2048 -keyout $_host1.key -out $_host1.csr -config $_host1.cnf
#echo "--- csr and key creation complete ---"
#echo " "
#echo "---------------------------"
#echo "-----Below is your CSR-----"
#echo "---------------------------"
#cat $_host1.csr
#echo
#echo
# >> Start Send csr to CA and retrieve certificate
CERT=`cat $_host1.csr | tr -d '\n\r'`
DATA="Mode=newreq&CertRequest=${CERT}&C&TargetStoreFlags=0&SaveCert=yes"
CERT=`echo ${CERT} | sed 's/+/%2B/g'`
CERT=`echo ${CERT} | tr -s ' ' '+'`
CERTATTRIB="CertificateTemplate:WebServerv2Exportable%0D%0A"
echo "2. Request cert from "$MSCA"..."
OUTPUTLINK=`curl -k -u "${Username}":${Password} --ntlm \
"https://${MSCA}/certsrv/certfnsh.asp" \
-H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' \
-H 'Accept-Encoding: gzip, deflate' \
-H 'Accept-Language: en-US,en;q=0.5' \
-H 'Connection: keep-alive' \
-H "Host: ${MSCA}" \
-H "Referer: https://${MSCA}/certsrv/certrqxt.asp" \
-H 'User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko' \
-H 'Content-Type: application/x-www-form-urlencoded' \
--data "Mode=newreq&CertRequest=${CERT}&CertAttrib=${CERTATTRIB}&TargetStoreFlags=0&SaveCert=yes&ThumbPrint=" | grep -A 1 'function handleGetCert() {' | tail -n 1 | cut -d '"' -f 2`
CERTLINK="https://${MSCA}/certsrv/${OUTPUTLINK}"
echo "3. Retrive cert: "$CERTLINK"..."
curl -k -u "${Username}":${Password} --ntlm $CERTLINK \
-H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' \
-H 'Accept-Encoding: gzip, deflate' \
-H 'Accept-Language: en-US,en;q=0.5' \
-H 'Connection: keep-alive' \
-H "Host: ${MSCA}" \
-H "Referer: https://${MSCA}/certsrv/certrqxt.asp" \
-H 'User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko' \
-H 'Content-Type: application/x-www-form-urlencoded' > $_host1.cer
echo "4. Verifying cert for "$_host1"..."
openssl verify -CAfile ca.cer -verbose $_host1.cer
if [ "0" -eq "$?" ] ;
then
echo "Certificate Validation Completed Succesfully"
echo
#exit 0
else
echo "Error code: "$?". Stopping."
exit 1
fi
#/END send csr to CA and retrieve certificate
if $_isWlan; then
echo "Do you need the certficate combined with the CA and key for Aruba IAP? [y/n]"
read _isIap
fi
if [ ${_isIap,,} == 'y' ] || [ ${_isIap,,} == 'yes' ]; then
echo "-------------------------------------------------------"
echo "----- Combining Server CA and Key file for VC -----"
echo "-------------------------------------------------------"
echo
# echo "-----Please Paste in the resulting PEM certificate-----"
# echo "----- then press [CTRL+D] to continue -----"
# echo "-------------------------------------------------------"
# _svrCert=$(</dev/stdin)
# echo "$_svrCert" > tmp.cer
# no error check right now for existing of CA.cer
mv $_host1.cer tmp.cer
cat ca.cer >> tmp.cer
cat $_host1.key >> tmp.cer
cat tmp.cer | sed '/^[[:space:]]*$/d' > $_host1.cer ##Remove blank lines
rm -f tmp.cer
echo "--------------------------------------------------"
echo "-----Cert Creation Complete. Combined cert ------"
echo "----- is in this directory "$_host1".cer ------"
echo "--------------------------------------------------"
else
echo "--------------------------------------------------"
echo "--------------------- DONE ---------------------"
echo "----- "$_host1".cer is in this directory ------"
echo "--------------------------------------------------"
fi
echo
echo Outputting Certificate Contents to Display...
sleep 4
clear
cat $_host1.cer
我在Java解决了。这是 class:
package com.qequipe.dsiglib.p10;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigInteger;
import java.net.Authenticator;
import java.net.HttpURLConnection;
import java.net.PasswordAuthentication;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.util.Base64;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSession;
import javax.security.auth.x500.X500Principal;
import org.spongycastle.operator.ContentSigner;
import org.spongycastle.operator.OperatorCreationException;
import org.spongycastle.operator.jcajce.JcaContentSignerBuilder;
import org.spongycastle.pkcs.PKCS10CertificationRequest;
import org.spongycastle.pkcs.PKCS10CertificationRequestBuilder;
import org.spongycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder;
import com.qequipe.dsiglib.util.FileUtil;
public class P10Generator {
public static byte[] generate(KeyPair pair) throws OperatorCreationException, IOException
{
//KeyPair pair = generateKeyPair();
PKCS10CertificationRequestBuilder p10Builder = new JcaPKCS10CertificationRequestBuilder(
new X500Principal("CN=Requested Test Certificate"), pair.getPublic());
JcaContentSignerBuilder csBuilder = new JcaContentSignerBuilder("SHA256withRSA");
ContentSigner signer = csBuilder.build(pair.getPrivate());
PKCS10CertificationRequest csr = p10Builder.build(signer);
return csr.getEncoded();
}
public static void main(String[] args)
{
try
{
KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA");
gen.initialize(2048);
KeyPair pair = gen.generateKeyPair();
byte[] pkcs10 = generate(pair);
String base64pkcs10 = new String(Base64.getEncoder().encode(pkcs10));
System.out.println(new BigInteger(1, pkcs10).toString(16));
System.out.println(base64pkcs10);
Date date = new Date();
Authenticator.setDefault(new Authenticator() {
@Override
public PasswordAuthentication getPasswordAuthentication() {
System.out.println("Scheme:" + getRequestingScheme());
return new PasswordAuthentication("\<username>", "password".toCharArray());
}
});
String request = "Mode=newreq&CertRequest=" + URLEncoder.encode(base64pkcs10) +
"&CertAttrib=" + URLEncoder.encode("CertificateTemplate:User\r\nUserAgent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36\r\n") +
"&FriendlyType=" + URLEncoder.encode("Saved-Request Certificate (" + (date.getDay()) + "/" + (date.getMonth() + 1) + "/" + date.getYear() + ", " + date.getHours() + ":" + date.getMinutes() + ":" + date.getSeconds() + ")") +
"&ThumbPrint=&TargetStoreFlags=0&SaveCert=yes";
byte[] cert = sendRequest("http://<yourcaurl>/certsrv/certfnsh.asp", request, "username", "password");
System.out.println(new BigInteger(1, cert).toString(16));
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
public static byte[] sendRequest(String urlString, String content, String username, String password) throws IOException {
HttpURLConnection con;
ByteArrayOutputStream out = new ByteArrayOutputStream();
URL url = new URL(urlString);
con = (HttpURLConnection) url.openConnection();
//String protocol = url.getProtocol();
con.setInstanceFollowRedirects(false);
con.setRequestMethod("POST");
//String encoded = Base64.getEncoder().encodeToString((username+":"+password).getBytes(StandardCharsets.UTF_8)); //Java 8
//con.setRequestProperty("Authorization", "NTML "+encoded);
con.setRequestProperty("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
con.setRequestProperty("Accept-Encoding","gzip, deflate");
con.setRequestProperty("Accept-Language", "en-US,en;q=0.5");
con.setRequestProperty("Connection","keep-alive");
con.setRequestProperty("Host", url.getHost());
con.setRequestProperty("Referer", url.getHost() + "/certsrv/certrqxt.asp");
con.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko");
con.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
con.setRequestProperty("Content-Length", "" + content.length());
con.setDoOutput(true);
OutputStream outs = con.getOutputStream();
outs.write(content.getBytes());
outs.flush();
BufferedInputStream bis = new BufferedInputStream(con.getInputStream());
int length;
while ((length = bis.read()) != -1) {
out.write(length);
}
out.close();
System.out.println(out);
int respCode;
System.out.println("RESP code = " + (respCode = con.getResponseCode()));
//System.out.println("RESPONSE = \n" + out);
if(con.getResponseCode() < HttpURLConnection.HTTP_BAD_REQUEST)
{
con.disconnect();
Pattern p = Pattern.compile("certnew.cer\?ReqID=(\d+)&");//. represents single character.
Matcher m = p.matcher(new String(out.toByteArray(), Charset.forName("UTF-8")));
if(m.find())
{
String reqid = m.group(1);
System.out.println(reqid);
URL certurl = new URL(url.getProtocol() +"://" + url.getHost() + "/certsrv/certnew.cer?ReqID=" + reqid + "&Enc=bin");
InputStream ins = certurl.openStream();
ByteArrayOutputStream bouts = new ByteArrayOutputStream();
FileUtil.copy(ins, bouts);
ins.close();
return bouts.toByteArray();
}
else
{
return null;
}
}
else
{
con.disconnect();
return null;
}
}
}