I want to sign xml file using enveloped signature approach in swift.
The example original xml file could be like below
<?xml version="1.0" encoding="ISO-8859-1"?>
<Envelope xmlns="http://example.org/envelope">
<Body>
Olá mundo
</Body>
</Envelope>
After signature, the xml file would be like this
<?xml version="1.0" encoding="ISO-8859-1"?>
<Envelope xmlns="http://example.org/envelope">
<Body>
Olá mundo
</Body>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
<Reference URI="">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<DigestValue>????</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>????</SignatureValue>
<KeyInfo>
<KeyValue>
<RSAKeyValue>????</RSAKeyValue>
</KeyValue>
</KeyInfo>
</Signature>
</Envelope>
Here the steps are
encrypt using sha1WithRSAEncryption signature algorithm (rsa-sha1), which uses the SHA-1 message digest algorithm and RSA PKCS#1v1.5 to create the signature.
Get the digest value using SHA-1
Canonicalization will be according to Canonical XML Version 1.0 or c14n rules.
Is there any library in swift or objective c which i can use for this purpose? I am currently using AEXML to parse, read and write xml file. But for canonical conversion and other steps stated above which library i can use?
For Your reference in C#, Cryptography.Xml provides all those functionalities. The below code in C# do the signing part of XML.
SignedXml signedXml = new SignedXml(xmlDocument);
signedXml.SigningKey = certificate.PrivateKey;
Reference reference = new Reference();
reference.Uri = ""; //"#" + procedureSerial;
reference.Type = reason;
reference.Id = DateTime.UtcNow.Ticks.ToString();
// Add an enveloped transformation to the reference.
XmlDsigEnvelopedSignatureTransform env = new XmlDsigEnvelopedSignatureTransform(true);
reference.AddTransform(env);
// Add the reference to the SignedXml object.
signedXml.AddReference(reference);
//canonicalize
XmlDsigC14NTransform c14t = new XmlDsigC14NTransform();
reference.AddTransform(c14t);
KeyInfo keyInfo = new KeyInfo();
KeyInfoX509Data keyInfoData = new KeyInfoX509Data(certificate);
KeyInfoName kin = new KeyInfoName();
kin.Value = certificate.FriendlyName;
RSA rsa = (RSA)certificate.PublicKey.Key;
RSAKeyValue rkv = new RSAKeyValue(rsa);
keyInfo.AddClause(rkv);
keyInfo.AddClause(kin);
keyInfo.AddClause(keyInfoData);
signedXml.KeyInfo = keyInfo;
// Compute the signature.
signedXml.ComputeSignature();
// Get the XML representation of the signature and save
// it to an XmlElement object.
XmlElement xmlDigitalSignature = signedXml.GetXml();
xmlDocument.DocumentElement.AppendChild(
xmlDocument.ImportNode(xmlDigitalSignature, true)
);
I want to do same functionalities using swift or objective C to sign xml file in MacOS.
Could you please suggest any library regarding this?
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Created
I have developed an application where i need to run a server locally. The application needs to call the local server by using http(http request from https). It works in chrome browser but whenever i want to run using safari browser it says "request cannot load due to access control check". I am using safari 16.3 version. Is there any way to allow access to mixed content in safari browser version 16+?
I am trying to import certificate in safenet dongle using swift and safenet's sdk. I have used encoder and decoder from the below linked code https://github.com/filom/ASN1Decoder. My swift side code is like below :-
let subjectDistinguishedNameDER = ASN1DEREncoder.encodeSequence(content: cert!.subjectDistinguishedNameDER)
let issuerDistinguishedNameDER = ASN1DEREncoder.encodeSequence(content: cert!.issuerDistinguishedNameDER)
dongle.importCertificate(password:donglePin, enrollmentId: id, subject: (subjectDistinguishedNameDER as CFData) as Data, issuer: (issuerDistinguishedNameDER as CFData) as Data, serialNumber: cert!.serialNumber!, value: (encodedData as CFData) as Data)
In the wrapper, I am doing below transformations
- (void) importCertificate:(NSString *) password enrollmentId:(NSString*)enrollmentId subject:(NSData*)subject issuer:(NSData*)issuer serialNumber:(NSData*)serialNumber value:(NSData*)value {
Dongle* d = (Dongle*)****;
char * eId = strdup([enrollmentId UTF8String]);
char * pass = strdup([password UTF8String]);
//char *signData = (char *)[data bytes];
unsigned char * sub = (unsigned char *)[subject bytes];
unsigned char * iss = (unsigned char *)[issuer bytes];
unsigned char * ser = (unsigned char *)[serialNumber bytes];
unsigned char * val = (unsigned char *)[value bytes];
NSUInteger valSize = [value length] / sizeof(unsigned char);
NSUInteger serSize = [serialNumber length] / sizeof(unsigned char);
NSUInteger issSize = [issuer length] / sizeof(unsigned char);
NSUInteger subSize = [subject length] / sizeof(unsigned char);
std::cout << "size size: \n";
//std::cout << size;
std::cout << "value print: \n";
d->importCertificate(pass, eId, sub, iss, ser, val, (int) subSize, (int) issSize, (int) serSize, (int) valSize);
}
in native side my methos is like :-
void Dongle::importCertificate(char *password, char* enrollmentId, unsigned char * subject, unsigned char * issuer, unsigned char * serialNumber, unsigned char * value, int subLength, int issLength, int serLength, int valLength) {
CK_RV rv = CKR_OK;
CK_BBOOL bFalse = CK_FALSE;
CK_BBOOL bTrue = CK_TRUE;
CK_KEY_TYPE keyType = CKK_RSA;
CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE;
LoadCryptoki(pkcs11_path);
rv = GetFirstSlotId(&slotId);
rv = C_OpenSession(slotId, (CKF_SERIAL_SESSION | CKF_RW_SESSION), NULL_PTR, NULL_PTR, &hSession);
// We can also use Dongle::generateKeyPairUtil
CK_OBJECT_HANDLE hPrivateKey = Dongle::getPrivateKeyHandle(hSession, password, enrollmentId);
CK_OBJECT_HANDLE hObject;
std::string labelPriv = std::string("private") + enrollmentId;
CK_UTF8CHAR * labelPrivate = convertToCK_UTF8CHAR(labelPriv); //Label of private key.
//std::string idPriv = std::string(enrollmentId);
//CK_UTF8CHAR * idPrivate = convertToCK_UTF8CHAR(idPriv);
CK_OBJECT_CLASS classCertificate = CKO_CERTIFICATE;
CK_OBJECT_CLASS typeCertificate = CKC_X_509;
CK_ATTRIBUTE certificateTemplate[] =
{
{ CKA_CLASS, &classCertificate, sizeof(classCertificate) },
{ CKA_TOKEN, &bTrue, sizeof(bTrue) },
{ CKA_PRIVATE, &bFalse, sizeof(bFalse) },
{ CKA_MODIFIABLE, &bTrue, sizeof(bTrue) },
{ CKA_LABEL, &labelPrivate, strlen((char *)labelPrivate) },
{ CKA_CERTIFICATE_TYPE, &typeCertificate, sizeof(typeCertificate) },
{ CKA_TRUSTED, &bFalse, sizeof(bFalse) },
{ CKA_SUBJECT, (CK_BYTE_PTR)&subject, (unsigned long)subLength },
{ CKA_ID, enrollmentId, strlen(enrollmentId) },
{ CKA_ISSUER, &issuer, strlen((char*) issuer) },
{ CKA_SERIAL_NUMBER, &serialNumber, strlen((char*) serialNumber) },
{ CKA_VALUE, (CK_BYTE_PTR)&value, (unsigned long)valLength }
};
std::cout << "length of subject \n";
std::cout << (unsigned long)subLength;
std::cout << "length of value \n";
std::cout << (unsigned long)valLength;
//CK_OBJECT_HANDLE hObject;
rv = C_CreateObject( hSession,
certificateTemplate,
DIM(certificateTemplate),
&hObject );
std::cout << "object handle code: \n";
std::cout << rv;
if (rv == CKR_OK) {
std::cout<< "Created object handle"<< hObject<< std::endl;
}
if (hSession) {
C_CloseSession(hSession);
UnloadCryptoki();
}
}
For certificate import, CKA_ISSUER and CKA_SERIAL_NUMBER are not necessary, I have also tried by removing them.
In Both case, I am getting CKA_TEMPLATE_INCONSISTENT code.
Is there any way I can get rid of this issue?
I have created public key and private key in my smartcard(Dongle) using safenet sdk's own library. I realized that Both are in PKCS#8 format. Both Private key and Public Key starts with "BEGIN PUBLIC KEY" and "BEGIN PRIVATE KEY" instead of "BEGIN RSA PUBLIC KEY" and "BEGIN RSA PRIVATE KEY".
I also signed CertificationInfo's(ex: Distinguished Names such as common name, postal code etc.). Then I am sending PubLic Key and the signed Data to my swift application to generate csr.
In csr generation step, I converted the public key to rsa format by removing first 32 characters, then convert it to SecKey to generate csr. I found that, after extracting seckey to Data, it is same before and after the SecKey conversion.
But, when i validate the signature with public key, It says that "Signature is invalid". Is it because the public key is in PKCS#1 format and the private key by whom the CertificationInfo is signed is in PKCS#8 format?
If this is the reason, what will be the probable fix to resolve the issue? Do i need to convert the Key format in native end(using C code)? What is the mechanism of generating PKCS#1 format key in C? Or, Is there any way to generate PKCS#8 SecKey using swift?
I am trying to convert publicKeyFromDongleData to SecKey, then perform some tasks. After that, I want to convert SecKey to b64 String. I am assuming that publicKeyFromDongleData and b64 string will be the same. But, surprisingly, they are not the same. How can i resolve the issue? Is there any way around?
My goal is to retain the public key before and after converting the same.
let publicKeyFromDongleData = Data.init(base64Encoded: publicKeyFromDongle)
guard let publicKeySecKey = SecKeyCreateWithData(publicKeyFromDongleData! as CFData, keyDict as CFDictionary, &error) else {
print("Failed to create public key:", error!.takeRetainedValue())
return nil
}
//var error:Unmanaged<CFError>?
if let cfdata = SecKeyCopyExternalRepresentation(publicKeySecKey, &error) {
let data:Data = cfdata as Data
let b64Key = data.base64EncodedString()
print("after : \n")
print(b64Key)
}
I am trying to build csr string from publickeyBits and signature from dongle. Below is the swift code portion for generating csr.
public func buildCSRAndReturnStringUsingDongle(enrollmentId: String, password: String) -> String? {
let tagPublic = "public" + enrollmentId
self.dongle = DongleManager.getInstance()
self.dongle?.generateKeyPair(enrollmentId: enrollmentId, password: password)
let publicKeyFromDongle: String = (self.dongle?.getPublicKeyBits(enrollmentId: enrollmentId, password: password))!
print("Public Key is: \n",publicKeyFromDongle)
let keyDict: [NSString: Any] = [
kSecAttrKeyType: kSecAttrKeyTypeRSA,
kSecAttrKeyClass: kSecAttrKeyClassPublic,
kSecAttrKeySizeInBits: 2048 as Any,
kSecAttrApplicationTag: tagPublic.data(using: .utf8),
]
var error: Unmanaged<CFError>?
let publicKeyFromDongleData = Data.init(base64Encoded: publicKeyFromDongle)
guard let publicKeySecKey = SecKeyCreateWithData(publicKeyFromDongleData! as CFData, keyDict as CFDictionary, &error) else {
print("Failed to create public key:", error!.takeRetainedValue())
return nil
}
let publickeyBits = KeyPairManager.getInstance().getPublicKeyBits(publicKey: publicKeySecKey, enrollmentId: enrollmentId).0
let certificationRequestInfo = buldCertificationRequestInfo(publickeyBits!)
let bytes: [UInt8] = certificationRequestInfo.map { $0 }
let certificationRequestStr = String(decoding: bytes, as: UTF8.self)
let signaturedString = self.dongle?.sign(password: password, data : certificationRequestStr, enrollmentId: enrollmentId)
var signature = [UInt8](repeating: 0, count: 256)
var signatureLen: Int = signature.count
let signatureData = signaturedString!.data(using: .hexadecimal)
signatureData!.copyBytes(to: &signature, count: signatureData!.count)
signatureLen = signatureData!.count
print("signature length: " + String(signatureLen))
print("signature: "+signatureData!.base64EncodedString())
var certificationRequest = Data(capacity: 1024)
certificationRequest.append(certificationRequestInfo)
let shaBytes = keyAlgorithm.sequenceObjectEncryptionType
certificationRequest.append(shaBytes, count: shaBytes.count)
var signData = Data(capacity: 2049)
let zero: UInt8 = 0 // Prepend zero
signData.append(zero)
signData.append(signature, count: signatureLen)
appendBITSTRING(signData, into: &certificationRequest)
enclose(&certificationRequest, by: sequenceTag) // Enclose into SEQUENCE
let csrString = certificationRequest.base64EncodedString(options: NSData.Base64EncodingOptions(rawValue: 0))
.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed)
print(csrString)
let head = "-----BEGIN CERTIFICATE REQUEST-----\n"
let foot = "-----END CERTIFICATE REQUEST-----\n"
var isMultiple = false
var newCSRString = head
//Check if string size is a multiple of 64
if csrString!.count % 64 == 0 {
isMultiple = true
}
for (integer, character) in csrString!.enumerated() {
newCSRString.append(character)
if (integer != 0) && ((integer + 1) % 64 == 0) {
newCSRString.append("\n")
}
if (integer == csrString!.count-1) && !isMultiple {
newCSRString.append("\n")
}
}
newCSRString += foot
return newCSRString
}
I wrote a Wrapper where sign function is as of given below. We had a getPublicBits() function here and i think that is working properly. So, I skip this here.
- (NSString*) sign: (NSString*)password data: (NSString*)data enrollmentId: (NSString*)enrollmentId {
Dongle *d = (Dongle*)dong;
char * pass = strdup([password UTF8String]);
char * signDataStr = strdup([data UTF8String]);
char * enId = strdup([enrollmentId UTF8String]);
NSData* data2 = [data dataUsingEncoding:NSUTF8StringEncoding];
char *signData = (char *)[data2 bytes];
NSString* signaturedString = [NSString stringWithCString:d->sign(pass, signData, enId).c_str() encoding:[NSString defaultCStringEncoding]];
return signaturedString;
}
I used signUtil method from safenet sdk's library.
std::string Dongle::signUtil(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hPrivateKey, char* password, char* data) {
//std::cout<<"data is: " << *data;
CK_RV retCode = CKR_OK;
int isPaddingRequired = 0;
int isDataFromUser = 0;
CK_MECHANISM mech;
CK_BYTE pSigData[3000];
#ifndef PKCS11_V1
CK_ULONG usSigLen = sizeof(pSigData);
#else
CK_ULONG usSigLen = 0;
#endif
char *pInputData = 0;
unsigned long ulInputDataLen = strlen(data);
std::cout << "length: " << ulInputDataLen;
CK_BYTE_PTR pInData = (CK_BYTE_PTR)data;
std::cout << "Mechanism: [6]SHA256-RSA" <<std::endl;
retCode = C_Login(hSession, CKU_USER, (CK_UTF8CHAR_PTR)password, strlen(password));
mech.mechanism = CKM_SHA256_RSA_PKCS;
mech.pParameter = 0;
mech.ulParameterLen = 0;
isDataFromUser = 0;
if( retCode == CKR_OK )
{
if( isPaddingRequired )
{
for(unsigned long ulLoop=ulInputDataLen; ulLoop<64; ++ulLoop)
{
pInData[ulLoop] = 0;
}
ulInputDataLen = 64;
}
}
if (retCode == CKR_OK)
{
retCode = C_SignInit(hSession, &mech, hPrivateKey);
}
CK_ULONG usInLen = (CK_ULONG)ulInputDataLen;
// get the signature length
if(retCode == CKR_OK)
{
retCode = C_Sign(hSession, pInData, usInLen, (CK_BYTE_PTR)NULL_PTR, &usSigLen);
}
// get the signature
if(retCode == CKR_OK)
{
retCode = C_Sign(hSession, pInData, usInLen, (CK_BYTE_PTR)pSigData, &usSigLen);
}
std::string returnSignature = "";
if( (retCode == CKR_OK) && usSigLen )
{
std::cout << "Signed Data " << std::endl << "(hex) ";
for(unsigned long ulLoop=0; ulLoop<usSigLen; ++ulLoop)
{
char pBuffer[25];
sprintf(pBuffer, "%02x", pSigData[ulLoop]);
std::cout << pBuffer;
returnSignature += pBuffer;
}
std::cout << std::endl;
}
// Release memory
if( pInputData )
{
delete pInputData;
}
return returnSignature;
}
I debug a lot and according to csr decoder, only the signature is invalid. public key and signature algorithm are valid.
I am trying to create SecKey from Public Key Data.
let publicKeyFromDongle: String = (self.dongle?.getPublicKeyBits(enrollmentId: enrollmentId, password: password))!
print("Public Key is: \n",publicKeyFromDongle)
let keyDict: [NSString: AnyObject] = [
kSecAttrKeyType: kSecAttrKeyTypeRSA,
kSecAttrKeyClass: kSecAttrKeyClassPublic,
kSecAttrKeySizeInBits: 2048 as AnyObject
]
var error: Unmanaged<CFError>?
print(publicKeyFromDongle.data(using: .utf8) as! CFData)
guard let publicKeySecKey = SecKeyCreateWithData(publicKeyFromDongle.data(using: .utf8) as! CFData, keyDict as CFDictionary, &error) else {
print("Failed to create public key:", error!.takeRetainedValue())
return nil
}
My PublicKeyFromDongle String is
MIIBozANBgkqhkiG9w0BAQEFAAOCAZAAMIIBiwKCAYEA9c242509d83c90f556972efed7d81acc307fcc02824798e7a142e4940eec727aaea8946494c295d69b388a53d462b364e990b039ca3fae0307b17514585f58b21b2503257939b983ae44c8c9018192d18eae513321234adda3330cc742aa8a4ef2fa01208ab13d8e5fb06c5cb95b3caaf8715d7dc2ddc1724d672ac2b29ff303bd61c4e3b0fbca47ade2756285bff71352a530440b500a0830896e456873fb42ec1b31c9693d5e22b627284586dd1842705ed24fca2450ff062dfbbf2dc7fccda567ed2f2b16ba8905e68b755021d1e87ff274205fa67b65b9bfa54fd49ccfb4240748f76c810666cab8f3ec92ec972fbd240b5ef56726965dd26d595d6403ebAgQA0100
How can i resolve it?
I have got below string by parsing a p7b string to get certificate chain. I want to parse only user certificate from this in swift. How can i know what is my user's certificate? Actually I need to parse only my certificate. I have gone through the decoding file and found that there is 2 commonName SEQUENCE named by my name MUHAMMAD AHAD UL ALAM.
I have attached a file having the ASN1 informations after decoding.
test.txt