📄 pkcs15-gpk.c
字号:
} return SC_ERROR_NOT_SUPPORTED;}/* * Set up the public key record for a signature only public key */static intgpk_pkfile_init_public(struct sc_profile *profile, struct sc_card *card, struct sc_file *file, unsigned int algo, unsigned int bits, unsigned int usage){ const struct sc_acl_entry *acl; u8 sysrec[7], buffer[256]; unsigned int n, npins; int r, gpkclass; /* Find out what sort of GPK we're using */ if ((r = sc_card_ctl(card, SC_CARDCTL_GPK_VARIANT, &gpkclass)) < 0) return r; /* Set up the system record */ memset(sysrec, 0, sizeof(sysrec)); /* XXX: How to map keyUsage to sysrec[2]? * 0x00 sign & unwrap * 0x10 sign only * 0x20 unwrap only * 0x30 CA key * Which PKCS15 key usage values map to which flag? */ sysrec[2] = 0x00; /* no restriction for now */ /* Set the key type and algorithm */ if ((r = gpk_pkfile_keybits(bits, &sysrec[1])) < 0 || (r = gpk_pkfile_keyalgo(algo, &sysrec[5])) < 0) return r; /* Set PIN protection if requested. */ acl = sc_file_get_acl_entry(file, SC_AC_OP_CRYPTO); for (npins = 0; acl; acl = acl->next) { if (acl->method == SC_AC_NONE || acl->method == SC_AC_NEVER) continue; if (acl->method != SC_AC_CHV) { error(profile, "Authentication method not " "supported for private key files.\n"); return SC_ERROR_NOT_SUPPORTED; } if (++npins >= 2) { error(profile, "Too many pins for PrKEY file!\n"); return SC_ERROR_NOT_SUPPORTED; } sysrec[2] += 0x40; sysrec[3] >>= 4; sysrec[3] |= acl->key_ref << 4; } /* compute checksum - yet another slightly different * checksum algorithm courtesy of Gemplus */ if (gpkclass >= 8000) { /* This is according to the gpk reference manual */ sysrec[6] = 0xA5; } else { /* And this is what you have to use for the GPK4000 */ sysrec[6] = 0xFF; } for (n = 0; n < 6; n++) sysrec[6] ^= sysrec[n]; card->ctx->log_errors = 0; r = sc_read_record(card, 1, buffer, sizeof(buffer), SC_RECORD_BY_REC_NR); card->ctx->log_errors = 1; if (r >= 0) { if (r != 7 || buffer[0] != 0) { error(profile, "first record of public key file is not Lsys0"); return SC_ERROR_OBJECT_NOT_VALID; } r = sc_update_record(card, 1, sysrec, sizeof(sysrec), SC_RECORD_BY_REC_NR); } else { r = sc_append_record(card, sysrec, sizeof(sysrec), 0); } return r;}static intgpk_pkfile_update_public(struct sc_profile *profile, struct sc_card *card, struct pkpart *part){ struct pkcomp *pe; unsigned char buffer[256]; unsigned int m, n, tag; int r = 0, found; if (card->ctx->debug > 1) debug(profile, "Updating public key elements\n"); /* If we've been given a key with public parts, write them now */ for (n = 2; n < 256; n++) { card->ctx->log_errors = 0; r = sc_read_record(card, n, buffer, sizeof(buffer), SC_RECORD_BY_REC_NR); card->ctx->log_errors = 1; if (r < 0) { r = 0; break; } /* Check for bad record */ if (r < 2) { error(profile, "key file format error: " "record %u too small (%u bytes)\n", n, r); return SC_ERROR_OBJECT_NOT_VALID; } tag = buffer[0]; for (m = 0, found = 0; m < part->count; m++) { pe = part->components + m; if (pe->tag == tag) { r = sc_update_record(card, n, pe->data, pe->size, SC_RECORD_BY_REC_NR); if (r < 0) return r; pe->tag = 0; /* mark as stored */ found++; break; } } if (!found && card->ctx->debug) debug(profile, "GPK unknown PK tag %u\n", tag); } /* Write all remaining elements */ for (m = 0; r >= 0 && m < part->count; m++) { pe = part->components + m; if (pe->tag != 0) r = sc_append_record(card, pe->data, pe->size, 0); } return r;}static intgpk_pkfile_init_private(struct sc_card *card, struct sc_file *file, unsigned int privlen){ struct sc_cardctl_gpk_pkinit args; args.file = file; args.privlen = privlen; return sc_card_ctl(card, SC_CARDCTL_GPK_PKINIT, &args);}static intgpk_pkfile_load_private(struct sc_card *card, struct sc_file *file, u8 *data, unsigned int len, unsigned int datalen){ struct sc_cardctl_gpk_pkload args; args.file = file; args.data = data; args.len = len; args.datalen = datalen; return sc_card_ctl(card, SC_CARDCTL_GPK_PKLOAD, &args);}static intgpk_pkfile_update_private(struct sc_profile *profile, struct sc_card *card, struct sc_file *file, struct pkpart *part){ unsigned int m, size, nb, cks; struct pkcomp *pe; u8 keybuf[32], data[256]; size_t keysize; int r = 0; if (card->ctx->debug > 1) debug(profile, "Updating private key elements\n"); /* We must set a secure messaging key before each Load Private Key * command. Any key will do... * The GPK _is_ weird. */ keysize = sizeof(keybuf); r = sc_pkcs15init_get_secret(profile, card, SC_AC_PRO, 1, keybuf, &keysize); if (r < 0) { error(profile, "No secure messaging key defined by profile"); return SC_ERROR_SECURITY_STATUS_NOT_SATISFIED; } for (m = 0; m < part->count; m++) { pe = part->components + m; if (pe->size + 8 > sizeof(data)) return SC_ERROR_BUFFER_TOO_SMALL; memcpy(data, pe->data, pe->size); size = pe->size; r = sc_verify(card, SC_AC_PRO, 1, keybuf, keysize, NULL); if (r < 0) break; /* Pad out data to a multiple of 8 and checksum. * The GPK manual is a bit unclear about whether you * checksum first and then pad, or vice versa. * The following code does seem to work though: */ for (nb = 0, cks = 0xff; nb < size; nb++) cks ^= data[nb]; data[nb++] = cks; while (nb & 7) data[nb++] = 0; r = gpk_pkfile_load_private(card, file, data, size-1, nb); if (r < 0) break; pe++; } return r;}/* Sum up the size of the public key elements * Each element is type + tag + bignum */static voidgpk_compute_publen(struct pkpart *part){ unsigned int n, publen = 8; /* length of sysrec0 */ for (n = 0; n < part->count; n++) publen += 2 + part->components[n].size; part->size = (publen + 3) & ~3UL;}/* Sum up the size of the private key elements * Each element is type + tag + bignum + checksum, padded to a multiple * of eight */static voidgpk_compute_privlen(struct pkpart *part){ unsigned int n, privlen = 8; for (n = 0; n < part->count; n++) privlen += (3 + part->components[n].size + 7) & ~7UL; part->size = privlen;}/* * Convert BIGNUM to GPK representation, optionally zero padding to size. * Note that the bignum's we're given are big-endian, while the GPK * wants them little-endian. */static voidgpk_bn2bin(unsigned char *dest, sc_pkcs15_bignum_t *bn, unsigned int size){ u8 *src; unsigned int n; assert(bn->len <= size); memset(dest, 0, size); for (n = bn->len, src = bn->data; n--; src++) dest[n] = *src;}/* * Add a BIGNUM component, optionally padding out the number to size bytes */static voidgpk_add_bignum(struct pkpart *part, unsigned int tag, sc_pkcs15_bignum_t *bn, size_t size){ struct pkcomp *comp; if (size == 0) size = bn->len; comp = &part->components[part->count++]; memset(comp, 0, sizeof(*comp)); comp->tag = tag; comp->size = size + 1; comp->data = (u8 *) malloc(size + 1); /* Add the tag */ comp->data[0] = tag; /* Add the BIGNUM */ gpk_bn2bin(comp->data + 1, bn, size); /* printf("TAG 0x%02x, len=%u\n", tag, comp->size); */}intgpk_encode_rsa_key(struct sc_profile *profile, struct sc_pkcs15_prkey_rsa *rsa, struct pkdata *p, struct sc_pkcs15_prkey_info *info){ if (!rsa->modulus.len || !rsa->exponent.len) { error(profile, "incomplete RSA public key"); return SC_ERROR_INVALID_ARGUMENTS; } /* Make sure the exponent is 0x10001 because that's * the only exponent supported by GPK4000 and GPK8000 */ if (rsa->exponent.len != 3 || memcmp(rsa->exponent.data, "\001\000\001", 3)) { error(profile, "unsupported RSA exponent"); return SC_ERROR_INVALID_ARGUMENTS; } memset(p, 0, sizeof(*p)); p->algo = SC_ALGORITHM_RSA; p->usage = info->usage; p->bytes = rsa->modulus.len; p->bits = p->bytes << 3; /* Set up the list of public elements */ gpk_add_bignum(&p->_public, 0x01, &rsa->modulus, 0); gpk_add_bignum(&p->_public, 0x07, &rsa->exponent, 0); /* Set up the list of private elements */ if (!rsa->p.len || !rsa->q.len || !rsa->dmp1.len || !rsa->dmq1.len || !rsa->iqmp.len) { /* No or incomplete CRT information */ if (!rsa->d.len) { error(profile, "incomplete RSA private key"); return SC_ERROR_INVALID_ARGUMENTS; } gpk_add_bignum(&p->_private, 0x04, &rsa->d, 0); } else if (5 * (p->bytes / 2) < 256) { /* All CRT elements are stored in one record */ struct pkcomp *comp; unsigned int K = p->bytes / 2; u8 *crtbuf; crtbuf = (u8 *) malloc(5 * K + 1); crtbuf[0] = 0x05; gpk_bn2bin(crtbuf + 1 + 0 * K, &rsa->p, K); gpk_bn2bin(crtbuf + 1 + 1 * K, &rsa->q, K); gpk_bn2bin(crtbuf + 1 + 2 * K, &rsa->iqmp, K); gpk_bn2bin(crtbuf + 1 + 3 * K, &rsa->dmp1, K); gpk_bn2bin(crtbuf + 1 + 4 * K, &rsa->dmq1, K); comp = &p->_private.components[p->_private.count++]; comp->tag = 0x05; comp->size = 5 * K + 1; comp->data = crtbuf; } else { /* CRT elements stored in individual records. * Make sure they're all fixed length even if they're * shorter */ gpk_add_bignum(&p->_private, 0x51, &rsa->p, p->bytes/2); gpk_add_bignum(&p->_private, 0x52, &rsa->q, p->bytes/2); gpk_add_bignum(&p->_private, 0x53, &rsa->iqmp, p->bytes/2); gpk_add_bignum(&p->_private, 0x54, &rsa->dmp1, p->bytes/2); gpk_add_bignum(&p->_private, 0x55, &rsa->dmq1, p->bytes/2); } return 0;}/* * Encode a DSA key. * Confusingly, the GPK manual says that the GPK8000 can handle * DSA with 512 as well as 1024 bits, but all byte sizes shown * in the tables are 512 bits only... */intgpk_encode_dsa_key(struct sc_profile *profile, struct sc_pkcs15_prkey_dsa *dsa, struct pkdata *p, struct sc_pkcs15_prkey_info *info){ if (!dsa->p.len || !dsa->q.len || !dsa->g.len || !dsa->pub.len || !dsa->priv.len) { error(profile, "incomplete DSA public key"); return SC_ERROR_INVALID_ARGUMENTS; } memset(p, 0, sizeof(*p)); p->algo = SC_ALGORITHM_RSA; p->usage = info->usage; p->bytes = dsa->q.len; p->bits = dsa->q.len << 3; /* Make sure the key is either 512 or 1024 bits */ if (p->bytes <= 64) { p->bits = 512; p->bytes = 64; } else if (p->bytes <= 128) { p->bits = 1024; p->bytes = 128; } else { error(profile, "incompatible DSA key size (%u bits)", p->bits); return SC_ERROR_INVALID_ARGUMENTS; } /* Set up the list of public elements */ gpk_add_bignum(&p->_public, 0x09, &dsa->p, 0); gpk_add_bignum(&p->_public, 0x0a, &dsa->q, 0); gpk_add_bignum(&p->_public, 0x0b, &dsa->g, 0); gpk_add_bignum(&p->_public, 0x0c, &dsa->pub, 0); /* Set up the list of private elements */ gpk_add_bignum(&p->_private, 0x0d, &dsa->priv, 0); return 0;}static intgpk_store_pk(struct sc_profile *profile, struct sc_card *card, struct sc_file *file, struct pkdata *p){ int r; /* Compute length of private/public key parts */ gpk_compute_publen(&p->_public); gpk_compute_privlen(&p->_private); if (card->ctx->debug) debug(profile, "Storing pk: %u bits, pub %u bytes, priv %u bytes\n", p->bits, p->_public.size, p->_private.size); file->size = p->_public.size + p->_private.size; r = gpk_pkfile_create(profile, card, file); if (r < 0) return r; /* Put the system record */ r = gpk_pkfile_init_public(profile, card, file, p->algo, p->bits, p->usage); if (r < 0) return r; /* Put the public key elements */ r = gpk_pkfile_update_public(profile, card, &p->_public); if (r < 0) return r; /* Create the private key part */ r = gpk_pkfile_init_private(card, file, p->_private.size); if (r < 0) return r; /* Now store the private key elements */ r = gpk_pkfile_update_private(profile, card, file, &p->_private); return r;}static voiderror(struct sc_profile *profile, const char *fmt, ...){ char buffer[256]; va_list ap; va_start(ap, fmt); vsnprintf(buffer, sizeof(buffer), fmt, ap); va_end(ap); if (profile->cbs && profile->cbs->error) profile->cbs->error("%s", buffer);}static voiddebug(struct sc_profile *profile, const char *fmt, ...){ char buffer[256]; va_list ap; va_start(ap, fmt); vsnprintf(buffer, sizeof(buffer), fmt, ap); va_end(ap); if (profile->cbs && profile->cbs->debug) profile->cbs->debug("%s", buffer); printf("%s", buffer); /* XXX */}struct sc_pkcs15init_operations sc_pkcs15init_gpk_operations = { gpk_erase_card, gpk_init_app, gpk_new_pin, gpk_new_key, gpk_new_file,};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -