static int decodeKeyAttributes(unsigned char *ka, int kalen, struct p15PrivateKeyDescription *p15) { int tag,len; unsigned char *po, *obj; po = obj = ka; tag = asn1Tag(&po); len = asn1Length(&po); if ((tag != ASN1_SEQUENCE) || (len <= 0)) { return -1; } po += len; if ((po - ka) >= kalen) { return 0; } obj = po; tag = asn1Tag(&po); len = asn1Length(&po); if ((tag == ASN1_INTEGER) && (len > 0)) { if (asn1DecodeInteger(po, len, &p15->keysize) < 0) { return -1; } } else { p15->keysize = 2048; // Save default for key size } return 0; }
/** * Decode a TLV encoded PKCS#15 private key description into a structure * * The caller must use freePrivateKeyDescription() to free the allocated structure * * @param prkd The first byte of the encoded structure * @param prkdlen The length of the encoded structure * @param p15 Pointer to pointer updated with the newly allocated structure * @return 0 if successfull, -1 for structural errors */ int decodePrivateKeyDescription(unsigned char *prkd, size_t prkdlen, struct p15PrivateKeyDescription **p15) { int rc,tag,len; unsigned char *po; rc = asn1Validate(prkd, prkdlen); if (rc != 0) { return -1; } *p15 = calloc(1, sizeof(struct p15PrivateKeyDescription)); if (*p15 == NULL) { return -1; } po = prkd; tag = asn1Tag(&po); len = asn1Length(&po); if ((tag != ASN1_SEQUENCE) && (tag != 0xA0)) { return -1; } (*p15)->keytype = (int)tag; rc = decodePrivateKeyAttributes(po, len, *p15); return rc; }
/** * Decode a TLV encoded PKCS#15 certificate description into a structure * * The caller must use freeCertificateDescription() to free the allocated structure * * @param cd The first byte of the encoded structure * @param cdlen The length of the encoded structure * @param p15 Pointer to pointer updated with the newly allocated structure * @return 0 if successful, -1 for structural errors */ int decodeCertificateDescription(unsigned char *cd, size_t cdlen, struct p15CertificateDescription **p15) { int rc,tag,len; unsigned char *po; rc = asn1Validate(cd, cdlen); if (rc != 0) { return -1; } *p15 = calloc(1, sizeof(struct p15CertificateDescription)); if (*p15 == NULL) { return -1; } po = cd; tag = asn1Tag(&po); len = asn1Length(&po); if ((tag != ASN1_SEQUENCE) && (tag != 0xA0)) { return -1; } (*p15)->certtype = (int)tag; rc = decodeCertificateAttributes(po, len, *p15); return rc; }
static int decodeCommonCertificateAttributes(unsigned char *cca, int ccalen, struct p15CertificateDescription *p15) { int tag,len; unsigned char *po, *obj, *id; if (ccalen <= 0) return 0; po = obj = cca; tag = asn1Tag(&po); len = asn1Length(&po); if ((tag != ASN1_OCTET_STRING) || (len <= 0)) { return -1; } id = calloc(len, 1); if (id == NULL) { return -1; } memcpy(id, po, len); p15->id.val = id; p15->id.len = len; po += len; return 0; }
static int decodeCertificateAttributes(unsigned char *cd, int cdlen, struct p15CertificateDescription *p15) { int rc,tag,len; unsigned char *po, *obj; if (cdlen <= 0) { // Nothing to decode return 0; } po = obj = cd; tag = asn1Tag(&po); if (tag != ASN1_SEQUENCE) { return -1; } len = asn1Length(&po); rc = decodeCommonObjectAttributes(po, len, &p15->coa); if (rc < 0) { return rc; } po += len; if ((po - cd) >= cdlen) { return 0; } obj = po; tag = asn1Tag(&po); if (tag != ASN1_SEQUENCE) { return -1; } len = asn1Length(&po); rc = decodeCommonCertificateAttributes(po, len, p15); if (rc < 0) { return rc; } po += len; return 0; }
static int decodeCommonKeyAttributes(unsigned char *cka, int ckalen, struct p15PrivateKeyDescription *p15) { int tag,len; unsigned char *po, *obj, *id; if (ckalen <= 0) return 0; po = obj = cka; tag = asn1Tag(&po); len = asn1Length(&po); if ((tag != ASN1_OCTET_STRING) || (len <= 0)) { return -1; } id = calloc(len, 1); if (id == NULL) { return -1; } memcpy(id, po, len); p15->id.val = id; p15->id.len = len; po += len; if ((po - cka) >= ckalen) { return 0; } obj = po; tag = asn1Tag(&po); len = asn1Length(&po); if ((tag != ASN1_BIT_STRING) || (len <= 1)) { return -1; } asn1DecodeFlags(po + 1, len - 1, &p15->usage); return 0; }
int decodeECParamsFromSPKI(unsigned char *spki, CK_ATTRIBUTE_PTR ecparams) { int tag, length, buflen; unsigned char *value, *cursor; cursor = spki; // spk is ASN.1 validated before, not need to check again // subjectPublicKeyInfo tag = asn1Tag(&cursor); if (tag != ASN1_SEQUENCE) { return -1; } buflen = asn1Length(&cursor); // algorithm if (!asn1Next(&cursor, &buflen, &tag, &length, &value)) { return -1; } if (tag != ASN1_SEQUENCE) { return -1; } cursor = value; buflen = length; // algorithm if (!asn1Next(&cursor, &buflen, &tag, &length, &value)) { return -1; } if (tag != ASN1_OBJECT_IDENTIFIER) { return -1; } ecparams->type = CKA_EC_PARAMS; ecparams->pValue = cursor; // parameters if (!asn1Next(&cursor, &buflen, &tag, &length, &value)) { return -1; } ecparams->ulValueLen = (CK_ULONG)(cursor - (unsigned char *)ecparams->pValue); return 0; }
static int decodeCommonObjectAttributes(unsigned char *coa, int coalen, struct p15CommonObjectAttributes *p15) { int tag,len; unsigned char *po; char *label; po = coa; tag = asn1Tag(&po); if (tag == ASN1_UTF8String) { len = asn1Length(&po); label = calloc(len + 1, 1); if (label == NULL) { return -1; } memcpy(label, po, len); p15->label = label; } return 0; }
static int decodePrivateKeyAttributes(unsigned char *prkd, int prkdlen, struct p15PrivateKeyDescription *p15) { int rc,tag,len; unsigned char *po, *obj; if (prkdlen <= 0) { // Nothing to decode return 0; } po = obj = prkd; tag = asn1Tag(&po); if (tag != ASN1_SEQUENCE) { return -1; } len = asn1Length(&po); rc = decodeCommonObjectAttributes(po, len, &p15->coa); if (rc < 0) { return rc; } po += len; if ((po - prkd) >= prkdlen) { return 0; } obj = po; tag = asn1Tag(&po); if (tag != ASN1_SEQUENCE) { return -1; } len = asn1Length(&po); rc = decodeCommonKeyAttributes(po, len, p15); if (rc < 0) { return rc; } po += len; if ((po - prkd) >= prkdlen) { return 0; } obj = po; tag = asn1Tag(&po); if (tag == 0xA0) { len = asn1Length(&po); po += len; if ((po - prkd) >= prkdlen) { return 0; } obj = po; tag = asn1Tag(&po); } len = asn1Length(&po); if ((tag != 0xA1) || (len <= 0)) { return -1; } tag = asn1Tag(&po); len = asn1Length(&po); if ((tag != ASN1_SEQUENCE) || (len <= 0)) { return -1; } rc = decodeKeyAttributes(po, len, p15); if (rc < 0) { return rc; } return 0; }
int decodeModulusExponentFromSPKI(unsigned char *spki, CK_ATTRIBUTE_PTR modulus, CK_ATTRIBUTE_PTR exponent) { int tag, length, buflen; unsigned char *value, *cursor; cursor = spki; // spk is ASN.1 validated before, not need to check again // subjectPublicKeyInfo tag = asn1Tag(&cursor); if (tag != ASN1_SEQUENCE) { return -1; } buflen = asn1Length(&cursor); // algorithm if (!asn1Next(&cursor, &buflen, &tag, &length, &value)) { return -1; } if (tag != ASN1_SEQUENCE) { return -1; } // subjectPublicKey if (!asn1Next(&cursor, &buflen, &tag, &length, &value)) { return -1; } if (tag != ASN1_BIT_STRING) { return -1; } if (length < 6) { return -1; } cursor = value + 1; buflen = length - 1; if (asn1Validate(cursor, buflen) != 0) { return -1; } // Outer SEQUENCE if (!asn1Next(&cursor, &buflen, &tag, &length, &value)) { return -1; } if (tag != ASN1_SEQUENCE) { return -1; } cursor = value; buflen = length; // Modulus if (!asn1Next(&cursor, &buflen, &tag, &length, &value)) { return -1; } if (tag != ASN1_INTEGER) { return -1; } modulus->type = CKA_MODULUS; modulus->pValue = value; modulus->ulValueLen = length; // Exponent if (!asn1Next(&cursor, &buflen, &tag, &length, &value)) { return -1; } if (tag != ASN1_INTEGER) { return -1; } exponent->type = CKA_PUBLIC_EXPONENT; exponent->pValue = value; exponent->ulValueLen = length; return 0; }
static int decodeECDSASignature(unsigned char *data, int datalen, unsigned char *out, int outlen) { int fieldsizebytes, i, r, taglen; unsigned char *po, *value; FUNC_CALLED(); r = asn1Validate(data, datalen); if (r != 0) { FUNC_FAILS(-1, "Signature is not a valid TLV structure"); } // Determine field size from length of signature if (datalen <= 58) { // 192 bit curve = 24 * 2 + 10 byte maximum DER signature fieldsizebytes = 24; } else if (datalen <= 66) { // 224 bit curve = 28 * 2 + 10 byte maximum DER signature fieldsizebytes = 28; } else if (datalen <= 74) { // 256 bit curve = 32 * 2 + 10 byte maximum DER signature fieldsizebytes = 32; } else if (datalen <= 90) { // 320 bit curve = 40 * 2 + 10 byte maximum DER signature fieldsizebytes = 40; } else { fieldsizebytes = 64; } #ifdef DEBUG debug("Field size %d, signature buffer size %d\n", fieldsizebytes, outlen); #endif if (outlen < (fieldsizebytes * 2)) { FUNC_FAILS(-1, "output too small for EC signature"); } memset(out, 0, outlen); po = data; if (asn1Tag(&po) != ASN1_SEQUENCE) { FUNC_FAILS(-1, "Signature not encapsulated in SEQUENCE"); } r = asn1Length(&po); if ((r < 8) || (r > 137)) { FUNC_FAILS(-1, "Invalid signature size"); } for (i = 0; i < 2; i++) { if (asn1Tag(&po) != ASN1_INTEGER) { FUNC_FAILS(-1, "Coordinate not encapsulated in INTEGER"); } taglen = asn1Length(&po); value = po; po += taglen; if (taglen > fieldsizebytes) { /* drop leading 00 if present */ if (*value != 0x00) { FUNC_FAILS(-1, "Invalid value in coordinate"); } value++; taglen--; } memcpy(out + fieldsizebytes * i + fieldsizebytes - taglen , value, taglen); } FUNC_RETURNS(fieldsizebytes << 1); }
int check_2pay_sys(unsigned char *rsp, int lr) { char *MC_RID = "\xA0\x00\x00\x00\x04"; /* MasterCard RID */ char *MC_UK_RID = "\xA0\x00\x00\x00\x05"; /* MasterCard UK RID */ char *VISA_RID = "\xA0\x00\x00\x00\x03"; /* Visa RID */ char *AMEX_RID = "\xA0\x00\x00\x00\x25"; /* AMEX RID */ char *DISCOVER_RID = "\xA0\x00\x00\x03\x24"; /* AMEX RID */ char *GIROGO_RID = "\xD2\x76\x00\x00\x25"; /* Geldkarte/GiroGo RID */ unsigned char *fci_issuer_discret_data; int fci_issuer_discret_data_len = 0; unsigned char *aid = NULL; int aid_len; unsigned char *app_template = NULL; int app_template_len = 0; unsigned char *tmp_aid = NULL; int tmp_aid_len; unsigned char *app_label = NULL; int app_label_len = 0; int priority = 15; unsigned char *prio = NULL; int prio_len; unsigned char *d; fci_issuer_discret_data = asn1Find(rsp, "\x6F\xA5\xBF\x0C", 3); if (fci_issuer_discret_data == NULL) return -1; asn1Tag(&fci_issuer_discret_data); fci_issuer_discret_data_len = asn1Length(&fci_issuer_discret_data); while (fci_issuer_discret_data_len > 4) { app_template = asn1Find(fci_issuer_discret_data, "\x61", 1); if (app_template == NULL) break; asn1Tag(&app_template); app_template_len = asn1Length(&app_template); d = app_template; /* Decode the AID */ tmp_aid = asn1Find(d, "\x4F", 1); if (tmp_aid == NULL) return -1; asn1Tag(&tmp_aid); tmp_aid_len = asn1Length(&tmp_aid); d = tmp_aid + tmp_aid_len; /* Decode the application label */ app_label = asn1Find(d, "\x50", 1); if (app_label != NULL) { asn1Tag(&app_label); app_label_len = asn1Length(&app_label); d = app_label + app_label_len; } /* Decode the priority */ prio = asn1Find(d, "\x87", 1); if (prio != NULL) { asn1Tag(&prio); prio_len = asn1Length(&prio); d = prio + prio_len; if (*prio < priority) { priority = *prio; aid = tmp_aid; aid_len = tmp_aid_len; } } else { aid = tmp_aid; aid_len = tmp_aid_len; } fci_issuer_discret_data_len -= app_template_len; fci_issuer_discret_data = d; } if (aid == NULL) return -1; /* We need at least the first five bytes of the AID (RID) */ if (aid_len < 5) return -1; if ((memcmp(aid, MC_RID, 5) == 0) || (memcmp(aid, MC_UK_RID, 5) == 0)) return 1; else if (memcmp(aid, VISA_RID, 5) == 0) return 2; else if (memcmp(aid, AMEX_RID, 5) == 0) return 3; else if (memcmp(aid, DISCOVER_RID, 5) == 0) return 4; else if (memcmp(aid, GIROGO_RID, 5) == 0) return 5; /* AID (RID) not supported */ return -1; }
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); }