diff options
author | Jason Wright <jason@cvs.openbsd.org> | 2003-08-20 16:28:36 +0000 |
---|---|---|
committer | Jason Wright <jason@cvs.openbsd.org> | 2003-08-20 16:28:36 +0000 |
commit | 081a7b677351d2522fe49ee563b546c059729d29 (patch) | |
tree | 30e366e7e1b00250e181c4148e3ac1b315348d89 /sys/dev | |
parent | 4a9331a4d5ec0960cf3c1adb263a86577c02fe86 (diff) |
most of the infrastructure to support public key operation. This is just
a snapshot of work in progress (doesn't work correctly yet).
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/pci/safe.c | 289 | ||||
-rw-r--r-- | sys/dev/pci/safereg.h | 21 | ||||
-rw-r--r-- | sys/dev/pci/safevar.h | 16 |
3 files changed, 304 insertions, 22 deletions
diff --git a/sys/dev/pci/safe.c b/sys/dev/pci/safe.c index 9d6024132e1..ff1bc73da35 100644 --- a/sys/dev/pci/safe.c +++ b/sys/dev/pci/safe.c @@ -1,4 +1,4 @@ -/* $OpenBSD: safe.c,v 1.6 2003/08/14 18:46:41 jason Exp $ */ +/* $OpenBSD: safe.c,v 1.7 2003/08/20 16:28:35 jason Exp $ */ /*- * Copyright (c) 2003 Sam Leffler, Errno Consulting @@ -85,6 +85,14 @@ int safe_intr(void *); int safe_newsession(u_int32_t *, struct cryptoini *); int safe_freesession(u_int64_t); int safe_process(struct cryptop *); +int safe_kprocess(struct cryptkop *); +int safe_kstart(struct safe_softc *); +void safe_kload_reg(struct safe_softc *, u_int32_t, u_int32_t, + struct crparam *); +struct safe_softc *safe_kfind(struct cryptkop *); +void safe_kpoll(void *); +void safe_kfeed(struct safe_softc *); +int safe_ksigbits(struct crparam *cr); void safe_callback(struct safe_softc *, struct safe_ringentry *); void safe_feed(struct safe_softc *, struct safe_ringentry *); void safe_mcopy(struct mbuf *, struct mbuf *, u_int); @@ -158,6 +166,7 @@ safe_attach(struct device *parent, struct device *self, void *aux) /* XXX handle power management */ + SIMPLEQ_INIT(&sc->sc_pkq); sc->sc_dmat = pa->pa_dmat; cmd = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG); @@ -270,17 +279,17 @@ safe_attach(struct device *parent, struct device *self, void *aux) if (devinfo & SAFE_DEVINFO_RNG) printf(" rng"); - bzero(algs, sizeof(algs)); #ifdef notyet - /* Key ops not supported yet */ + bzero(algs, sizeof(algs)); if (devinfo & SAFE_DEVINFO_PKEY) { printf(" key"); - crypto_kregister(sc->sc_cid, CRK_MOD_EXP, 0, - safe_kprocess, sc); - crypto_kregister(sc->sc_cid, CRK_MOD_EXP_CRT, 0, - safe_kprocess, sc); + algs[CRK_MOD_EXP] = CRYPTO_ALG_FLAG_SUPPORTED; + crypto_kregister(sc->sc_cid, algs, safe_kprocess); + timeout_set(&sc->sc_pkto, safe_kpoll, sc); } #endif + + bzero(algs, sizeof(algs)); if (devinfo & SAFE_DEVINFO_DES) { printf(" des/3des"); algs[CRYPTO_3DES_CBC] = CRYPTO_ALG_FLAG_SUPPORTED; @@ -935,10 +944,10 @@ safe_process(struct cryptop *crp) */ sa->sa_cmd0 = cmd0 | SAFE_SA_CMD0_IPCI | SAFE_SA_CMD0_OPCI; sa->sa_cmd1 = cmd1 - | (coffset << SAFE_SA_CMD1_OFFSET_S) - | SAFE_SA_CMD1_SAREV1 /* Rev 1 SA data structure */ - | SAFE_SA_CMD1_SRPCI - ; + | (coffset << SAFE_SA_CMD1_OFFSET_S) + | SAFE_SA_CMD1_SAREV1 /* Rev 1 SA data structure */ + | SAFE_SA_CMD1_SRPCI; + /* * NB: the order of writes is important here. In case the * chip is scanning the ring because of an outstanding request @@ -1026,6 +1035,9 @@ safe_init_board(struct safe_softc *sc) ; WRITE_REG(sc, SAFE_PE_DMACFG, v); + WRITE_REG(sc, SAFE_CRYPTO_CTRL, SAFE_CRYPTO_CTRL_PKEY | + SAFE_CRYPTO_CTRL_3DES | SAFE_CRYPTO_CTRL_RNG); + #if BYTE_ORDER == LITTLE_ENDIAN WRITE_REG(sc, SAFE_ENDIAN, SAFE_ENDIAN_TGT_PASS|SAFE_ENDIAN_DMA_PASS); #elif BYTE_ORDER == BIG_ENDIAN @@ -1072,7 +1084,7 @@ safe_init_board(struct safe_softc *sc) */ WRITE_REG(sc, SAFE_PE_PARTCFG, SAFE_MAX_DSIZE); -/*XXX*/ WRITE_REG(sc, SAFE_HI_CLR, SAFE_INT_PE_CDONE | SAFE_INT_PE_DDONE | + WRITE_REG(sc, SAFE_HI_CLR, SAFE_INT_PE_CDONE | SAFE_INT_PE_DDONE | SAFE_INT_PE_ERROR | SAFE_INT_PE_ODONE); /* it's now safe to enable PE mode, do it */ @@ -1790,6 +1802,259 @@ safe_intr(void *arg) return (1); } +struct safe_softc * +safe_kfind(struct cryptkop *krp) +{ + struct safe_softc *sc; + int i; + + for (i = 0; i < safe_cd.cd_ndevs; i++) { + sc = safe_cd.cd_devs[i]; + if (sc == NULL) + continue; + if (sc->sc_cid == krp->krp_hid) + return (sc); + } + return (NULL); +} + +int +safe_kprocess(struct cryptkop *krp) +{ + struct safe_softc *sc; + struct safe_pkq *q; + int s; + + if ((sc = safe_kfind(krp)) == NULL) { + krp->krp_status = EINVAL; + goto err; + } + + if (krp->krp_op != CRK_MOD_EXP) { + krp->krp_status = EOPNOTSUPP; + goto err; + } + + q = (struct safe_pkq *)malloc(sizeof(*q), M_DEVBUF, M_NOWAIT); + if (q == NULL) { + krp->krp_status = ENOMEM; + goto err; + } + q->pkq_krp = krp; + + s = splnet(); + SIMPLEQ_INSERT_TAIL(&sc->sc_pkq, q, pkq_next); + safe_kfeed(sc); + splx(s); + return (0); + +err: + crypto_kdone(krp); + return (0); +} + +#define SAFE_CRK_PARAM_BASE 0 +#define SAFE_CRK_PARAM_EXP 1 +#define SAFE_CRK_PARAM_MOD 2 + +int +safe_kstart(struct safe_softc *sc) +{ + struct cryptkop *krp = sc->sc_pkq_cur->pkq_krp; + int exp_bits, mod_bits, base_bits; + u_int32_t op, a_off, b_off, c_off, d_off; + + if (krp->krp_iparams < 3 || krp->krp_oparams != 1) { + krp->krp_status = EINVAL; + return (1); + } + + base_bits = safe_ksigbits(&krp->krp_param[SAFE_CRK_PARAM_BASE]); + if (base_bits > 2048) + goto too_big; + if (base_bits <= 0) /* 5. base not zero */ + goto too_small; + + exp_bits = safe_ksigbits(&krp->krp_param[SAFE_CRK_PARAM_EXP]); + if (exp_bits > 2048) + goto too_big; + if (exp_bits <= 0) /* 1. exponent word length > 0 */ + goto too_small; /* 4. exponent not zero */ + + mod_bits = safe_ksigbits(&krp->krp_param[SAFE_CRK_PARAM_MOD]); + if (mod_bits > 2048) + goto too_big; + if (mod_bits <= 32) /* 2. modulus word length > 1 */ + goto too_small; /* 8. MSW of modulus != zero */ + if (mod_bits < exp_bits) /* 3 modulus len >= exponent len */ + goto too_small; + if ((krp->krp_param[SAFE_CRK_PARAM_MOD].crp_p[0] & 1) == 0) + goto bad_domain; /* 6. modulus is odd */ + if (mod_bits > krp->krp_param[krp->krp_iparams].crp_nbits) + goto too_small; /* make sure result will fit */ + + /* 7. modulus > base */ + if (mod_bits < base_bits) + goto too_small; + if (mod_bits == base_bits) { + u_int8_t *basep, *modp; + int i; + + basep = krp->krp_param[SAFE_CRK_PARAM_BASE].crp_p + + ((base_bits + 7) / 8) - 1; + modp = krp->krp_param[SAFE_CRK_PARAM_MOD].crp_p + + ((mod_bits + 7) / 8) - 1; + + for (i = 0; i < (mod_bits + 7) / 8; i++, basep--, modp--) { + if (*modp < *basep) + goto too_small; + if (*modp > *basep) + break; + } + } + + /* And on the 9th step, he rested. */ + + WRITE_REG(sc, SAFE_PK_A_LEN, (exp_bits + 31) / 32); + WRITE_REG(sc, SAFE_PK_B_LEN, (mod_bits + 31) / 32); + if (mod_bits > 1024) { + op = SAFE_PK_FUNC_EXP4; + a_off = 0x000; + b_off = 0x100; + c_off = 0x200; + d_off = 0x300; + } else { + op = SAFE_PK_FUNC_EXP16; + a_off = 0x000; + b_off = 0x080; + c_off = 0x100; + d_off = 0x180; + } + sc->sc_pk_reslen = b_off - a_off; + sc->sc_pk_resoff = d_off; + + /* A is exponent, B is modulus, C is base, D is result */ + safe_kload_reg(sc, a_off, b_off - a_off, + &krp->krp_param[SAFE_CRK_PARAM_EXP]); + WRITE_REG(sc, SAFE_PK_A_ADDR, a_off >> 2); + safe_kload_reg(sc, a_off, b_off - a_off, + &krp->krp_param[SAFE_CRK_PARAM_MOD]); + WRITE_REG(sc, SAFE_PK_B_ADDR, b_off >> 2); + safe_kload_reg(sc, a_off, b_off - a_off, + &krp->krp_param[SAFE_CRK_PARAM_BASE]); + WRITE_REG(sc, SAFE_PK_C_ADDR, c_off >> 2); + WRITE_REG(sc, SAFE_PK_D_ADDR, d_off >> 2); + + WRITE_REG(sc, SAFE_PK_FUNC, op | SAFE_PK_FUNC_RUN); + + return (0); + +too_big: + krp->krp_status = E2BIG; + return (1); +too_small: + krp->krp_status = ERANGE; + return (1); +bad_domain: + krp->krp_status = EDOM; + return (1); +} + +int +safe_ksigbits(struct crparam *cr) +{ + u_int plen = (cr->crp_nbits + 7) / 8; + int i, sig = plen * 8; + u_int8_t c, *p = cr->crp_p; + + for (i = plen - 1; i >= 0; i--) { + c = p[i]; + if (c != 0) { + while ((c & 0x80) == 0) { + sig--; + c <<= 1; + } + break; + } + sig -= 8; + } + return (sig); +} + +void +safe_kfeed(struct safe_softc *sc) +{ + if (SIMPLEQ_EMPTY(&sc->sc_pkq) && sc->sc_pkq_cur == NULL) + return; + if (sc->sc_pkq_cur != NULL) + return; + while (!SIMPLEQ_EMPTY(&sc->sc_pkq)) { + struct safe_pkq *q = SIMPLEQ_FIRST(&sc->sc_pkq); + + sc->sc_pkq_cur = q; + SIMPLEQ_REMOVE_HEAD(&sc->sc_pkq, q, pkq_next); + if (safe_kstart(sc) != 0) { + crypto_kdone(q->pkq_krp); + free(q, M_DEVBUF); + sc->sc_pkq_cur = NULL; + } else { + /* op started, start polling */ + timeout_add(&sc->sc_pkto, 1); + break; + } + } +} + +void +safe_kpoll(void *vsc) +{ + struct safe_softc *sc = vsc; + struct safe_pkq *q; + struct crparam *res; + int s, i; + u_int32_t buf[64]; + + if (sc->sc_pkq_cur == NULL) + return; + if (READ_REG(sc, SAFE_PK_FUNC) & SAFE_PK_FUNC_RUN) { + /* still running, check back later */ + timeout_add(&sc->sc_pkto, 1); + return; + } + + q = sc->sc_pkq_cur; + res = &q->pkq_krp->krp_param[q->pkq_krp->krp_iparams]; + bzero(buf, sizeof(buf)); + bzero(res->crp_p, (res->crp_nbits + 7) / 8); + for (i = 0; i < sc->sc_pk_reslen >> 2; i++) + buf[i] = READ_REG(sc, SAFE_PK_RAM_START + sc->sc_pk_resoff + + (i << 2)); + bcopy(buf, res->crp_p, sc->sc_pk_reslen); + res->crp_nbits = sc->sc_pk_reslen * 8; + res->crp_nbits = safe_ksigbits(res); + + crypto_kdone(q->pkq_krp); + free(q, M_DEVBUF); + sc->sc_pkq_cur = NULL; + + s = splnet(); + safe_kfeed(sc); + splx(s); +} + +void +safe_kload_reg(struct safe_softc *sc, u_int32_t off, u_int32_t len, + struct crparam *n) +{ + u_int32_t buf[64], i; + + bzero(buf, sizeof(buf)); + bcopy(n->crp_p, buf, (n->crp_nbits + 7) / 8); + + for (i = 0; i < len >> 2; i++) + WRITE_REG(sc, SAFE_PK_RAM_START + off + (i << 2), buf[i]); +} + #ifdef SAFE_DEBUG void diff --git a/sys/dev/pci/safereg.h b/sys/dev/pci/safereg.h index ca4d406e6e9..a3ea0fc0908 100644 --- a/sys/dev/pci/safereg.h +++ b/sys/dev/pci/safereg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: safereg.h,v 1.3 2003/08/14 18:53:36 jason Exp $ */ +/* $OpenBSD: safereg.h,v 1.4 2003/08/20 16:28:35 jason Exp $ */ /*- * Copyright (c) 2003 Sam Leffler, Errno Consulting @@ -77,14 +77,6 @@ #define SAFE_DMA_STAT 0x00cc /* DMA Current Status */ #define SAFE_DMA_CFG 0x00d4 /* DMA Configuration/Status */ #define SAFE_ENDIAN 0x00e0 /* Endian Configuration */ -#define SAFE_PK_A_ADDR 0x0800 /* Public Key A Address */ -#define SAFE_PK_B_ADDR 0x0804 /* Public Key B Address */ -#define SAFE_PK_C_ADDR 0x0808 /* Public Key C Address */ -#define SAFE_PK_D_ADDR 0x080c /* Public Key D Address */ -#define SAFE_PK_A_LEN 0x0810 /* Public Key A Length */ -#define SAFE_PK_B_LEN 0x0814 /* Public Key B Length */ -#define SAFE_PK_SHIFT 0x0818 /* Public Key Shift */ -#define SAFE_PK_FUNC 0x081c /* Public Key Function */ #define SAFE_RNG_OUT 0x0100 /* RNG Output */ #define SAFE_RNG_STAT 0x0104 /* RNG Status */ #define SAFE_RNG_CTRL 0x0108 /* RNG Control */ @@ -100,6 +92,16 @@ #define SAFE_RNG_LFSR1_HI 0x0130 /* RNG LFSR1 [47:32] */ #define SAFE_RNG_LFSR2_LO 0x0134 /* RNG LFSR1 [31:0] */ #define SAFE_RNG_LFSR2_HI 0x0138 /* RNG LFSR1 [47:32] */ +#define SAFE_PK_A_ADDR 0x0800 /* Public Key A Address */ +#define SAFE_PK_B_ADDR 0x0804 /* Public Key B Address */ +#define SAFE_PK_C_ADDR 0x0808 /* Public Key C Address */ +#define SAFE_PK_D_ADDR 0x080c /* Public Key D Address */ +#define SAFE_PK_A_LEN 0x0810 /* Public Key A Length */ +#define SAFE_PK_B_LEN 0x0814 /* Public Key B Length */ +#define SAFE_PK_SHIFT 0x0818 /* Public Key Shift */ +#define SAFE_PK_FUNC 0x081c /* Public Key Function */ +#define SAFE_PK_RAM_START 0x1000 /* Public Key RAM start address */ +#define SAFE_PK_RAM_END 0x1fff /* Public Key RAM end address */ #define SAFE_PE_CSR_READY 0x00000001 /* ready for processing */ #define SAFE_PE_CSR_DONE 0x00000002 /* h/w completed processing */ @@ -265,6 +267,7 @@ #define SAFE_PK_FUNC_COPY 0x00000800 /* Copy function */ #define SAFE_PK_FUNC_EXP16 0x00002000 /* Exponentiate (4-bit ACT) */ #define SAFE_PK_FUNC_EXP4 0x00004000 /* Exponentiate (2-bit ACT) */ +#define SAFE_PK_FUNC_RUN 0x00008000 /* start/status */ #define SAFE_RNG_STAT_BUSY 0x00000001 /* busy, data not valid */ diff --git a/sys/dev/pci/safevar.h b/sys/dev/pci/safevar.h index 794857f621e..7b9fed21f69 100644 --- a/sys/dev/pci/safevar.h +++ b/sys/dev/pci/safevar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: safevar.h,v 1.4 2003/08/14 15:26:03 jason Exp $ */ +/* $OpenBSD: safevar.h,v 1.5 2003/08/20 16:28:35 jason Exp $ */ /*- * Copyright (c) 2003 Sam Leffler, Errno Consulting @@ -31,6 +31,11 @@ #ifndef _SAFE_SAFEVAR_H_ #define _SAFE_SAFEVAR_H_ +/* public key parameter locations */ +#define SAFE_CRK_PARAM_BASE 0 +#define SAFE_CRK_PARAM_EXP 1 +#define SAFE_CRK_PARAM_MOD 2 + /* Maximum queue length */ #ifndef SAFE_MAX_NQUEUE #define SAFE_MAX_NQUEUE 60 @@ -137,6 +142,11 @@ struct safe_session { u_int32_t ses_iv[4]; /* DES/3DES/AES iv */ }; +struct safe_pkq { + SIMPLEQ_ENTRY(safe_pkq) pkq_next; + struct cryptkop *pkq_krp; +}; + struct safe_softc { struct device sc_dev; /* device backpointer */ struct resource *sc_irq; @@ -167,6 +177,10 @@ struct safe_softc { struct safe_session *sc_sessions; /* sessions */ struct timeout sc_rngto; /* rng timeout */ + struct timeout sc_pkto; /* pk timeout */ + SIMPLEQ_HEAD(, safe_pkq) sc_pkq; + struct safe_pkq *sc_pkq_cur; + u_int32_t sc_pk_reslen, sc_pk_resoff; }; #endif /* _KERNEL */ |