Sample Code
Java
Verify signing_cert_url, signature that obtained in HTTP or HTTPS Message Format, and message (contained in the message signature) to check the message validity, as shown in the following:
private static void isMessageValid(String signing_cert_url, String signature, Map<String, String> message) {
InputStream in = null;
try {
URL url = new URL(signing_cert_url);
in = url.openStream();
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate) cf.generateCertificate(in);
Signature sig = Signature.getInstance(cert.getSigAlgName());
sig.initVerify(cert.getPublicKey());
sig.update(buildSignMessage(message).getBytes("UTF-8"));
byte[] sigByte = Base64.getDecoder().decode(signature);
if (sig.verify(sigByte)) {
System.out.println("Verify success");
} else {
System.out.println("Verify failed");
}
} catch (Exception e) {
throw new SecurityException("Verify method failed.", e);
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
If your Java version is earlier than 8, use the third-party package commons-codec.jar to perform Base64 decoding, and replace byte[] sigByte = Base64.getDecoder().decode(signature); with byte[] sigByte = Base64.decodeBase64(signature); in the preceding code.
The following is an example of the code to create the message verification signature:
private static String buildSignMessage(Map<String, String> msg) {
String type = msg.get("type");
String message = null;
if ("Notification".equals(type)) {
message = buildNotificationMessage(msg);
} else if ("SubscriptionConfirmation".equals(type) || "UnsubscribeConfirmation".equals(type)) {
message = buildSubscriptionMessage(msg);
} else if ("HttpSubscriptionUserConfirm".equals(type)) {
message = buildSubscriptionUserConfirmMessage(msg);
} else if ("HttpSubscriptionUserUnsubscribe".equals(type)) {
message = buildSubscriptionUserUnsubscribeMessage(msg);
}
return message;
}
private static String buildSubscriptionMessage(Map<String, String> msg) {
String stringMessage = "message\n";
stringMessage += msg.get("message") + "\n";
stringMessage += "message_id\n";
stringMessage += msg.get("message_id") + "\n";
stringMessage += "subscribe_url\n";
stringMessage += msg.get("subscribe_url") + "\n";
stringMessage += "timestamp\n";
stringMessage += msg.get("timestamp") + "\n";
stringMessage += "topic_urn\n";
stringMessage += msg.get("topic_urn") + "\n";
stringMessage += "type\n";
stringMessage += msg.get("type") + "\n";
return stringMessage;
}
private static String buildNotificationMessage(Map<String, String> msg) {
String stringMessage = "message\n";
stringMessage += msg.get("message").toString() + "\n";
stringMessage += "message_id\n";
stringMessage += msg.get("message_id").toString() + "\n";
if (msg.get("subject") != null) {
stringMessage += "subject\n";
stringMessage += msg.get("subject").toString() + "\n";
}
stringMessage += "timestamp\n";
stringMessage += msg.get("timestamp").toString() + "\n";
stringMessage += "topic_urn\n";
stringMessage += msg.get("topic_urn").toString() + "\n";
stringMessage += "type\n";
stringMessage += msg.get("type").toString() + "\n";
return stringMessage;
}
private static String buildSubscriptionUserConfirmMessage(Map<String, String> msg) {
String stringMessage = "message\n";
stringMessage += msg.get("message") + "\n";
stringMessage += "message_id\n";
stringMessage += msg.get("message_id") + "\n";
stringMessage += "subscribe_url\n";
stringMessage += msg.get("subscribe_url") + "\n";
stringMessage += "timestamp\n";
stringMessage += msg.get("timestamp") + "\n";
stringMessage += "type\n";
stringMessage += msg.get("type") + "\n";
return stringMessage;
}
private static String buildSubscriptionUserUnsubscribeMessage(Map<String, String> msg) {
String stringMessage = "message\n";
stringMessage += msg.get("message") + "\n";
stringMessage += "message_id\n";
stringMessage += msg.get("message_id") + "\n";
stringMessage += "timestamp\n";
stringMessage += msg.get("timestamp") + "\n";
stringMessage += "type\n";
stringMessage += msg.get("type") + "\n";
return stringMessage;
} Node.js
const fs = require('fs');
const crypto = require('crypto');
const jsrsag = require('jsrsasign');
/**
* Message signature verification
* @param pemFile Path for storing the signature file (local path of the downloaded certificate)
* @param signature Signature to be verified
*@param message Message content to be verified
* @returns {boolean} true: Signature verification succeeded. false: Signature verification failed.
*/
function verifyMessage(pemFile, signature, message) {
const pubPem = fs.readFileSync(pemFile);
const verify = crypto.createVerify(signatureAlgorithm(pubPem));
verify.update(buildSignMessage(message));
const verifyResult = verify.verify(pubPem, signature, 'base64');
if (verifyResult) {
console.log("verify success");
return true;
} else {
console.log('verify failed, result: ' + verifyResult);
return false;
}
}
/**
* Obtain the signature algorithm from the certificate.
*/
function signatureAlgorithm(pubPem) {
const certObject = new jsrsag.X509();
certObject.readCertPEM(pubPem.toString());
let algorithm = certObject.getSignatureAlgorithmField();
if (algorithm.split('with').length > 1) {
algorithm = algorithm.split('with')[1] + '-' + algorithm.split('with')[0];
}
return algorithm;
}
function buildSignMessage(msg) {
const type = msg.type;
let message = '';
if (type === 'Notification') {
message = buildNotificationMessage(msg);
} else if (type === 'SubscriptionConfirmation' || type === 'UnsubscribeConfirmation') {
message = buildSubscriptionMessage(msg);
} else if (type === 'HttpSubscriptionUserConfirm') {
message = buildSubscriptionUserConfirmMessage(msg);
} else if (type === 'HttpSubscriptionUserUnsubscribe') {
message = buildSubscriptionUserUnsubscribeMessage(msg);
}
return message;
}
function buildNotificationMessage(msg) {
let signMessage = 'message\n' + msg.message + '\n';
signMessage += 'message_id\n' + msg.message_id + '\n';
if (msg.subject) {
signMessage += 'subject\n' + msg.subject + '\n';
}
signMessage += 'timestamp\n' + msg.timestamp + '\n';
signMessage += 'topic_urn\n' + msg.topic_urn + '\n';
signMessage += 'type\n' + msg.type + '\n';
return signMessage;
}
function buildSubscriptionMessage(msg) {
let signMessage = 'message\n' + msg.message + '\n';
signMessage += 'message_id\n' + msg.message_id + '\n';
signMessage += 'subscribe_url\n' + msg.subscribe_url + '\n';
signMessage += 'timestamp\n' + msg.timestamp + '\n';
signMessage += 'topic_urn\n' + msg.topic_urn + '\n';
signMessage += 'type\n' + msg.type + '\n';
return signMessage;
}
function buildSubscriptionUserConfirmMessage(msg) {
let signMessage = 'message\n' + msg.message + '\n';
signMessage += 'message_id\n' + msg.message_id + '\n';
signMessage += 'subscribe_url\n' + msg.subscribe_url + '\n';
signMessage += 'timestamp\n' + msg.timestamp + '\n';
signMessage += 'type\n' + msg.type + '\n';
return signMessage;
}
function buildSubscriptionUserUnsubscribeMessage(msg) {
let signMessage = 'message\n' + msg.message + '\n';
signMessage += 'message_id\n' + msg.message_id + '\n';
signMessage += 'timestamp\n' + msg.timestamp + '\n';
signMessage += 'type\n' + msg.type + '\n';
return signMessage;
}
The sample code has passed the test on Nodejs v14.17.5.
Go
package demo
import (
"bytes"
"crypto"
"crypto/rsa"
"crypto/x509"
"encoding/base64"
"encoding/json"
"encoding/pem"
"fmt"
"io/ioutil"
)
type Message struct {
Signature string `json:"signature"`
Subject *string `json:"subject"`
TopicUrn string `json:"topic_urn"`
MessageId string `json:"message_id"`
SignatureVersion string `json:"signature_version"`
Type string `json:"type"`
Message string `json:"message"`
SubscribeUrl string `json:"subscribe_url"`
UnsubscribeUrl string `json:"unsubscribe_url"`
SigningCertUrl string `json:"signing_cert_url"`
Timestamp string `json:"timestamp"`
}
func VerifyMessage(pemFile string, message string) bool {
msg := Message{}
err := json.Unmarshal([]byte(message), &msg)
if err != nil {
fmt.Println("Convert json to struct failed")
return false
}
pemContent, err := ioutil.ReadFile(pemFile)
if err != nil {
fmt.Println("Read pem file failed")
return false
}
certDerblock, _ := pem.Decode(pemContent)
if certDerblock == nil {
fmt.Println("Decode pem file failed")
return false
}
cert, err := x509.ParseCertificate(certDerblock.Bytes)
if err != nil {
fmt.Println("Parse cert failed")
return false
}
msgString := buildMessage(&msg)
msgHash := crypto.SHA256.New()
msgHash.Write([]byte(msgString))
msgHashSum := msgHash.Sum(nil)
decodeSign, _ := base64.StdEncoding.DecodeString(msg.Signature)
publicKey := cert.PublicKey.(*rsa.PublicKey)
err = rsa.VerifyPKCS1v15(publicKey, crypto.SHA256, msgHashSum, decodeSign)
if err != nil {
fmt.Println("Verify failed")
return false
} else {
fmt.Println("Verify success")
return true
}
}
func buildMessage(msg *Message) string {
if msg.Type == "Notification" {
return buildNotificationMessage(msg)
} else if msg.Type == "SubscriptionConfirmation" || msg.Type == "UnsubscribeConfirmation" {
return buildSubscriptionMessage(msg)
} else if msg.Type == "HttpSubscriptionUserConfirm" {
return buildSubscriptionUserConfirmMessage(msg)
} else if msg.Type == "HttpSubscriptionUserUnsubscribe" {
return buildSubscriptionUserUnsubscribeMessage(msg)
}
return ""
}
func buildNotificationMessage(msg *Message) string {
buf := bytes.Buffer{}
buf.WriteString("message\n" + msg.Message + "\n")
buf.WriteString("message_id\n" + msg.MessageId + "\n")
// Special handling is required if the Subject field is missing from msg.
if msg.Subject != nil {
buf.WriteString("subject\n" + *msg.Subject + "\n")
}
buf.WriteString("timestamp\n" + msg.Timestamp + "\n")
buf.WriteString("topic_urn\n" + msg.TopicUrn + "\n")
buf.WriteString("type\n" + msg.Type + "\n")
return buf.String()
}
func buildSubscriptionMessage(msg *Message) string {
buf := bytes.Buffer{}
buf.WriteString("message\n" + msg.Message + "\n")
buf.WriteString("message_id\n" + msg.MessageId + "\n")
buf.WriteString("subscribe_url\n" + msg.SubscribeUrl + "\n")
buf.WriteString("timestamp\n" + msg.Timestamp + "\n")
buf.WriteString("topic_urn\n" + msg.TopicUrn + "\n")
buf.WriteString("type\n" + msg.Type + "\n")
return buf.String()
}
func buildSubscriptionUserConfirmMessage(msg *Message) string {
buf := bytes.Buffer{}
buf.WriteString("message\n" + msg.Message + "\n")
buf.WriteString("message_id\n" + msg.MessageId + "\n")
buf.WriteString("subscribe_url\n" + msg.SubscribeUrl + "\n")
buf.WriteString("timestamp\n" + msg.Timestamp + "\n")
buf.WriteString("type\n" + msg.Type + "\n")
return buf.String()
}
func buildSubscriptionUserUnsubscribeMessage(msg *Message) string {
buf := bytes.Buffer{}
buf.WriteString("message\n" + msg.Message + "\n")
buf.WriteString("message_id\n" + msg.MessageId + "\n")
buf.WriteString("timestamp\n" + msg.Timestamp + "\n")
buf.WriteString("type\n" + msg.Type + "\n")
return buf.String()
}
The sample code has passed the test on Go 11.5
What is your overall rating for this page?
Thank you very much for your feedback. We will continue working to improve the documentation.See the reply and handling status in My Cloud VOC.
For any further questions, feel free to contact us through the chatbot.
Chatbot