int starcosReadICCSN(struct p11Token_t *token) { static struct bytestring_s EFICCSN = { (unsigned char *)"\x2F\x02", 2 }; unsigned char scr[12],*s,*d; unsigned short SW1SW2; struct starcosPrivateData *sc; int rc,*sa; FUNC_CALLED(); // Clear currently selected application indicator sc = starcosGetPrivateData(token); if (token->slot->primarySlot) { sa = &(starcosGetPrivateData(getBaseToken(token))->selectedApplication); } else { sa = &sc->selectedApplication; } *sa = 0; // Select MF rc = transmitAPDU(token->slot, 0x00, 0xA4, 0x00, 0x0C, 0, NULL, 0, NULL, 0, &SW1SW2); if (rc < 0) { FUNC_FAILS(rc, "transmitAPDU failed"); } if (SW1SW2 != 0x9000) { FUNC_FAILS(-1, "Could not select MF"); } rc = starcosReadTLVEF(token, &EFICCSN, scr, sizeof(scr)); if (rc < 0) FUNC_FAILS(rc, "Reading EF.SN.ICC"); memset(token->info.serialNumber, ' ', sizeof(token->info.serialNumber)); s = scr + 4; // Ignore 5A08 and first two bytes as serial number is only 16 digits while ICCSN is 20 digits rc -= 4; d = token->info.serialNumber; while (rc > 0) { *d++ = bcddigit(*s >> 4); *d++ = bcddigit(*s & 15); s++; rc--; } return 0; }
static int checkPINStatus(struct p11Slot_t *slot) { int rc; unsigned short SW1SW2; FUNC_CALLED(); rc = transmitAPDU(slot, 0x00, 0x20, 0x00, 0x81, 0, NULL, 0, NULL, 0, &SW1SW2); if (rc < 0) { FUNC_FAILS(rc, "transmitAPDU failed"); } FUNC_RETURNS(SW1SW2); }
int starcosCheckPINStatus(struct p11Slot_t *slot, unsigned char pinref) { int rc; unsigned short SW1SW2; FUNC_CALLED(); rc = transmitAPDU(slot, 0x00, 0x20, 0x00, pinref, 0, NULL, 0, NULL, 0, &SW1SW2); if (rc < 0) { FUNC_FAILS(rc, "transmitAPDU failed"); } FUNC_RETURNS(SW1SW2); }
int starcosSwitchApplication(struct p11Token_t *token, struct starcosApplication *application) { int rc, *sa; unsigned short SW1SW2; struct starcosPrivateData *sc; FUNC_CALLED(); sc = starcosGetPrivateData(token); if (token->slot->primarySlot) { sa = &(starcosGetPrivateData(getBaseToken(token))->selectedApplication); } else { sa = &sc->selectedApplication; } if (application->aidId == *sa) { #ifdef DEBUG debug("Application %d already selected\n", *sa); #endif return 0; } #ifdef DEBUG debug("Switch to application %d\n", application->aidId); #endif rc = transmitAPDU(token->slot, 0x00, 0xA4, 0x04, 0x0C, (int)application->aid.len, application->aid.val, 0, NULL, 0, &SW1SW2); if (rc < 0) { FUNC_FAILS(rc, "transmitAPDU failed"); } if (SW1SW2 != 0x9000) { FUNC_FAILS(-1, "Selecting application failed"); } *sa = application->aidId; FUNC_RETURNS(0); }
static int enumerateObjects(struct p11Slot_t *slot, unsigned char *filelist, size_t len) { int rc; unsigned short SW1SW2; FUNC_CALLED(); rc = transmitAPDU(slot, 0x80, 0x58, 0x00, 0x00, 0, NULL, 65536, filelist, len, &SW1SW2); if (rc < 0) { FUNC_FAILS(rc, "transmitAPDU failed"); } if (SW1SW2 != 0x9000) { FUNC_FAILS(-1, "Token did not enumerate objects"); } FUNC_RETURNS(rc); }
static int selectApplet(struct p11Slot_t *slot) { int rc; unsigned short SW1SW2; FUNC_CALLED(); rc = transmitAPDU(slot, 0x00, 0xA4, 0x04, 0x0C, sizeof(aid), aid, 0, NULL, 0, &SW1SW2); if (rc < 0) { FUNC_FAILS(rc, "transmitAPDU failed"); } if (SW1SW2 != 0x9000) { FUNC_FAILS(-1, "Token is not a SmartCard-HSM"); } FUNC_RETURNS(CKR_OK); }
static int sc_hsm_C_Sign(struct p11Object_t *pObject, CK_MECHANISM_TYPE mech, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen) { int rc, algo, signaturelen; unsigned short SW1SW2; unsigned char scr[256]; FUNC_CALLED(); rc = getSignatureSize(mech, pObject); if (rc < 0) { FUNC_FAILS(CKR_MECHANISM_INVALID, "Unknown mechanism"); } signaturelen = rc; if (pSignature == NULL) { *pulSignatureLen = signaturelen; FUNC_RETURNS(CKR_OK); } if (*pulSignatureLen < signaturelen) { *pulSignatureLen = signaturelen; FUNC_FAILS(CKR_BUFFER_TOO_SMALL, "Signature length is larger than buffer"); } algo = getAlgorithmIdForSigning(mech); if (algo < 0) { FUNC_FAILS(CKR_MECHANISM_INVALID, "Mechanism not supported"); } if ((algo == ALGO_EC_RAW) || (algo == ALGO_EC_SHA1)) { rc = transmitAPDU(pObject->token->slot, 0x80, 0x68, (unsigned char)pObject->tokenid, (unsigned char)algo, ulDataLen, pData, 0, scr, sizeof(scr), &SW1SW2); } else { if (mech == CKM_RSA_PKCS) { if (signaturelen > sizeof(scr)) { FUNC_FAILS(CKR_BUFFER_TOO_SMALL, "Signature length is larger than buffer"); } applyPKCSPadding(pData, ulDataLen, scr, signaturelen); rc = transmitAPDU(pObject->token->slot, 0x80, 0x68, (unsigned char)pObject->tokenid, (unsigned char)algo, signaturelen, scr, 0, pSignature, *pulSignatureLen, &SW1SW2); } else { rc = transmitAPDU(pObject->token->slot, 0x80, 0x68, (unsigned char)pObject->tokenid, (unsigned char)algo, ulDataLen, pData, 0, pSignature, *pulSignatureLen, &SW1SW2); } } if (rc < 0) { FUNC_FAILS(CKR_DEVICE_ERROR, "transmitAPDU failed"); } if (SW1SW2 != 0x9000) { FUNC_FAILS(CKR_DEVICE_ERROR, "Signature operation failed"); } if ((algo == ALGO_EC_RAW) || (algo == ALGO_EC_SHA1)) { rc = decodeECDSASignature(scr, rc, pSignature, *pulSignatureLen); if (rc < 0) { FUNC_FAILS(CKR_BUFFER_TOO_SMALL, "supplied buffer too small"); } } *pulSignatureLen = rc; FUNC_RETURNS(CKR_OK); }
static int starcos_C_Sign(struct p11Object_t *pObject, CK_MECHANISM_TYPE mech, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen) { int rc, len, signaturelen; unsigned short SW1SW2; unsigned char scr[256],*s, *d; struct p11Slot_t *slot; FUNC_CALLED(); rc = getSignatureSize(mech, pObject); if (rc < 0) { FUNC_FAILS(CKR_MECHANISM_INVALID, "Unknown mechanism"); } signaturelen = rc; if (pSignature == NULL) { *pulSignatureLen = signaturelen; FUNC_RETURNS(CKR_OK); } if (*pulSignatureLen < (CK_ULONG)signaturelen) { *pulSignatureLen = signaturelen; FUNC_FAILS(CKR_BUFFER_TOO_SMALL, "Signature length is larger than buffer"); } slot = pObject->token->slot; starcosLock(pObject->token); if (!slot->token) { FUNC_RETURNS(CKR_DEVICE_REMOVED); } rc = starcosSelectApplication(pObject->token); if (rc < 0) { starcosUnlock(pObject->token); FUNC_FAILS(CKR_DEVICE_ERROR, "selecting application failed"); } if ((mech != CKM_RSA_PKCS) && (mech != CKM_ECDSA) && (mech != CKM_ECDSA_SHA1) && (mech != CKM_SC_HSM_PSS_SHA1) && (mech != CKM_SC_HSM_PSS_SHA224) && (mech != CKM_SC_HSM_PSS_SHA256) && (mech != CKM_SC_HSM_PSS_SHA384) && (mech != CKM_SC_HSM_PSS_SHA512)) { rc = starcosDigest(pObject->token, mech, pData, ulDataLen); if (rc != CKR_OK) { starcosUnlock(pObject->token); FUNC_FAILS(rc, "digesting failed"); } pData = NULL; ulDataLen = 0; } rc = getAlgorithmIdForSigning(pObject->token, mech, &s); if (rc != CKR_OK) { starcosUnlock(pObject->token); FUNC_FAILS(rc, "getAlgorithmIdForSigning() failed"); } d = scr; *d++ = *s++; len = *s; *d++ = *s++; while (len--) { *d++ = *s++; } *d++ = 0x84; *d++ = 0x01; *d++ = (unsigned char)pObject->tokenid; rc = transmitAPDU(pObject->token->slot, 0x00, 0x22, 0x41, 0xB6, (int)(d - scr), scr, 0, NULL, 0, &SW1SW2); if (rc < 0) { starcosUnlock(pObject->token); FUNC_FAILS(CKR_DEVICE_ERROR, "transmitAPDU failed"); } if (SW1SW2 != 0x9000) { starcosUnlock(pObject->token); FUNC_FAILS(CKR_DEVICE_ERROR, "MANAGE SE failed"); } rc = transmitAPDU(pObject->token->slot, 0x00, 0x2A, 0x9E, 0x9A, ulDataLen, pData, 0, pSignature, *pulSignatureLen, &SW1SW2); if (rc < 0) { starcosUnlock(pObject->token); FUNC_FAILS(CKR_DEVICE_ERROR, "transmitAPDU failed"); } if (SW1SW2 != 0x9000) { starcosUnlock(pObject->token); switch(SW1SW2) { case 0x6A81: FUNC_FAILS(CKR_KEY_FUNCTION_NOT_PERMITTED, "Signature operation not allowed for key"); break; case 0x6982: pObject->token->user = INT_CKU_NO_USER; FUNC_FAILS(CKR_USER_NOT_LOGGED_IN, "User not logged in"); break; } FUNC_FAILS(CKR_DEVICE_ERROR, "Signature operation failed"); } *pulSignatureLen = rc; if ((pObject->token->user == CKU_USER) && (pObject->token->pinUseCounter == 1)) { pObject->token->user = INT_CKU_NO_USER; } starcosUnlock(pObject->token); FUNC_RETURNS(CKR_OK); }
int starcosDigest(struct p11Token_t *token, CK_MECHANISM_TYPE mech, unsigned char *data, size_t len) { int rc; size_t chunk; unsigned short SW1SW2; unsigned char scr[1008],*algo, *po; FUNC_CALLED(); rc = getAlgorithmIdForDigest(token, mech, &algo); if (rc != CKR_OK) { FUNC_FAILS(rc, "getAlgorithmIdForDigest() failed"); } po = algo; asn1Tag(&po); rc = asn1Length(&po); rc += (int)(po - algo); rc = transmitAPDU(token->slot, 0x00, 0x22, 0x41, 0xAA, rc, algo, 0, NULL, 0, &SW1SW2); if (rc < 0) { FUNC_FAILS(CKR_DEVICE_ERROR, "transmitAPDU failed"); } if (SW1SW2 != 0x9000) { FUNC_FAILS(CKR_DEVICE_ERROR, "MANAGE SE failed"); } if (len <= 1000) { scr[0] = 0x90; scr[1] = 0x00; memcpy(scr + 2, data, len); rc = asn1Encap(0x80, scr + 2, (int)len) + 2; rc = transmitAPDU(token->slot, 0x00, 0x2A, 0x90, 0xA0, rc, scr, 0, NULL, 0, &SW1SW2); if (rc < 0) { FUNC_FAILS(CKR_DEVICE_ERROR, "transmitAPDU failed"); } if (SW1SW2 != 0x9000) { FUNC_FAILS(CKR_DEVICE_ERROR, "Hash operation failed"); } } else { scr[0] = 0x90; scr[1] = 0x00; rc = transmitAPDU(token->slot, 0x10, 0x2A, 0x90, 0xA0, 2, scr, 0, NULL, 0, &SW1SW2); if (rc < 0) { FUNC_FAILS(CKR_DEVICE_ERROR, "transmitAPDU failed"); } if (SW1SW2 != 0x9000) { FUNC_FAILS(CKR_DEVICE_ERROR, "Hash operation failed"); } while (len > 0) { chunk = (len > (size_t)token->drv->maxHashBlock ? (size_t)token->drv->maxHashBlock : len); memcpy(scr, data, chunk); rc = asn1Encap(0x80, scr, (int)chunk); rc = transmitAPDU(token->slot, len > chunk ? 0x10 : 0x00, 0x2A, 0x90, 0xA0, rc, scr, 0, NULL, 0, &SW1SW2); if (rc < 0) { FUNC_FAILS(CKR_DEVICE_ERROR, "transmitAPDU failed"); } if (SW1SW2 != 0x9000) { FUNC_FAILS(CKR_DEVICE_ERROR, "Hash operation failed"); } len -= chunk; data += chunk; } } return CKR_OK; }
int starcosDeterminePinUseCounter(struct p11Token_t *token, unsigned char recref, int *useCounter, int *lifeCycle) { int rc,ucpathlen; unsigned short SW1SW2; unsigned char rec[256], *p,*fid,*ucpath; FUNC_CALLED(); if (token->info.firmwareVersion.minor >= 5) { fid = (unsigned char *)"\x00\x13"; // EF.KEYD ucpath = (unsigned char *)"\x30\x7B\xA4\x9F\x22"; ucpathlen = 4; // 4 Tags (not bytes) } else { fid = (unsigned char *)"\x00\x15"; // EF.PWDD ucpath = (unsigned char *)"\x30\x7B\x9F\x22"; ucpathlen = 3; // 3 Tags (not bytes) } // Select EF rc = transmitAPDU(token->slot, 0x00, 0xA4, 0x02, 0x0C, 2, fid, 0, NULL, 0, &SW1SW2); if (rc < 0) { FUNC_FAILS(rc, "transmitAPDU failed"); } if (SW1SW2 != 0x9000) { FUNC_FAILS(-1, "File not found"); } // Read record, but leave 3 bytes to add encapsulating 30 81 FF later rc = transmitAPDU(token->slot, 0x00, 0xB2, recref, 0x04, 0, NULL, 0, rec, sizeof(rec) - 3, &SW1SW2); if (rc < 0) { FUNC_FAILS(rc, "transmitAPDU failed"); } if (SW1SW2 != 0x9000) { FUNC_FAILS(-1, "Record not found"); } rc = asn1Encap(0x30, rec, rc); rc = (int)asn1Validate(rec, rc); if (rc > 0) { FUNC_FAILS(rc, "ASN.1 structure invalid"); } *useCounter = 0; p = asn1Find(rec, ucpath, ucpathlen); if (p) { asn1Tag(&p); asn1Length(&p); *useCounter = (*p == 0xFF ? 0 : *p); } p = asn1Find(rec, (unsigned char *)"\x30\x8A", 2); if (p) { asn1Tag(&p); asn1Length(&p); *lifeCycle = *p; } FUNC_RETURNS(CKR_OK); }
int starcosReadTLVEF(struct p11Token_t *token, bytestring fid, unsigned char *content, size_t len) { int rc, le, tl, ne, maxapdu; size_t ofs; unsigned short SW1SW2; unsigned char *po; FUNC_CALLED(); // Select EF rc = transmitAPDU(token->slot, 0x00, 0xA4, 0x02, 0x0C, (int)fid->len, fid->val, 0, NULL, 0, &SW1SW2); if (rc < 0) { FUNC_FAILS(rc, "transmitAPDU failed"); } if (SW1SW2 != 0x9000) { FUNC_FAILS(-1, "File not found"); } // Read first block to determine tag and length rc = transmitAPDU(token->slot, 0x00, 0xB0, 0x00, 0x00, 0, NULL, 0, content, (int)len, &SW1SW2); if (rc < 0) { FUNC_FAILS(rc, "transmitAPDU failed"); } if (SW1SW2 != 0x9000) { FUNC_FAILS(-1, "Read EF failed"); } ofs = rc; // Restrict the number of bytes in Le to either the maximum APDU size of STARCOS or // the maximum APDU size of the reader, if any. maxapdu = token->drv->maxRAPDU; if (token->slot->maxRAPDU && (token->slot->maxRAPDU < maxapdu)) maxapdu = token->slot->maxRAPDU; maxapdu -= 2; // Accommodate SW1/SW2 le = 65536; // Read all if no certificate found if ((*content == 0x30) || (*content == 0x5A)) { po = content; asn1Tag(&po); tl = asn1Length(&po); tl += (int)(po - content); le = tl - (int)ofs; } while ((rc > 0) && (ofs < len) && (le > 0)) { ne = le; // Restrict Ne to the maximum APDU length allowed if (((le != 65536) || token->slot->noExtLengthReadAll) && (le > maxapdu)) ne = maxapdu; rc = transmitAPDU(token->slot, 0x00, 0xB0, (unsigned char)(ofs >> 8), (unsigned char)(ofs & 0xFF), 0, NULL, ne, content + ofs, (int)(len - ofs), &SW1SW2); if (rc < 0) { FUNC_FAILS(rc, "transmitAPDU failed"); } if ((SW1SW2 != 0x9000) && (SW1SW2 != 0x6B00) && (SW1SW2 != 0x6282)) { FUNC_FAILS(-1, "Read EF failed"); } ofs += rc; if (le != 65536) le -= rc; } FUNC_RETURNS((int)ofs); }