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.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
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
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 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 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 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?
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 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)
}