diff options
author | Werner Koch <[email protected]> | 2008-09-23 09:57:45 +0000 |
---|---|---|
committer | Werner Koch <[email protected]> | 2008-09-23 09:57:45 +0000 |
commit | f899b9683b7123b7bacd5de91fb49fd2412b9116 (patch) | |
tree | b6b89477ec7016c1d9902442db6a98e980d49a5f /scd/atr.c | |
parent | * keyserver.c (keyserver_import_cert): Allow keyserver URLs in (diff) | |
download | gnupg-f899b9683b7123b7bacd5de91fb49fd2412b9116.tar.gz gnupg-f899b9683b7123b7bacd5de91fb49fd2412b9116.zip |
Support the Certifciate DO of the v2 OpenPGP cards.
Diffstat (limited to 'scd/atr.c')
-rw-r--r-- | scd/atr.c | 111 |
1 files changed, 111 insertions, 0 deletions
@@ -277,10 +277,121 @@ atr_dump (int slot, FILE *fp) } +/* Note: This code has not yet been tested! It shall return -1 on + error or the nu,ber of hiostroical bytes and store them at + HISTORICAL. */ +int +atr_get_historical (int slot, unsigned char historical[]) +{ + int result = -1; + unsigned char *atrbuffer = NULL; + unsigned char *atr; + size_t atrlen; + int have_ta, have_tb, have_tc, have_td; + int n_historical; + int idx; + unsigned char chksum; + + atr = atrbuffer = apdu_get_atr (slot, &atrlen); + if (!atr || atrlen < 2) + goto leave; + atrlen--; + atr++; + + chksum = *atr; + for (idx=1; idx < atrlen-1; idx++) + chksum ^= atr[idx]; + + have_ta = !!(*atr & 0x10); + have_tb = !!(*atr & 0x20); + have_tc = !!(*atr & 0x40); + have_td = !!(*atr & 0x80); + n_historical = (*atr & 0x0f); + + if (have_ta + have_tb + have_tc + have_td + n_historical >= atrlen) + goto leave; /* ATR shorter than indicated by format character. */ + atrlen--; + atr++; + + if (have_ta + have_tb + have_tc >= atrlen) + goto leave; + atrlen -= have_ta + have_tb + have_tc; + atr += have_ta + have_tb + have_tc; + + if (have_td) + { + have_ta = !!(*atr & 0x10); + have_tb = !!(*atr & 0x20); + have_tc = !!(*atr & 0x40); + have_td = !!(*atr & 0x80); + if (have_ta + have_tb + have_tc + have_td + n_historical >= atrlen) + goto leave; /* ATR shorter than indicated by format character. */ + atrlen--; + atr++; + } + else + have_ta = have_tb = have_tc = have_td = 0; + + if (have_ta + have_tb + have_tc >= atrlen) + goto leave; + atrlen -= have_ta + have_tb + have_tc; + atr += have_ta + have_tb + have_tc; + + if (have_td) + { + have_ta = !!(*atr & 0x10); + have_tb = !!(*atr & 0x20); + have_tc = !!(*atr & 0x40); + have_td = !!(*atr & 0x80); + if (have_ta + have_tb + have_tc + have_td + n_historical >= atrlen) + goto leave; /* ATR shorter than indicated by format character. */ + atrlen--; + atr++; + } + else + have_ta = have_tb = have_tc = have_td = 0; + + for (idx = 3; have_ta || have_tb || have_tc || have_td; idx++) + { + if (have_ta + have_tb + have_tc >= atrlen) + goto leave; + atrlen -= have_ta + have_tb + have_tc; + atr += have_ta + have_tb + have_tc; + + if (have_td) + { + have_ta = !!(*atr & 0x10); + have_tb = !!(*atr & 0x20); + have_tc = !!(*atr & 0x40); + have_td = !!(*atr & 0x80); + if (have_ta + have_tb + have_tc + have_td + n_historical >= atrlen) + goto leave; /* ATR shorter than indicated by format character. */ + atrlen--; + atr++; + } + else + have_ta = have_tb = have_tc = have_td = 0; + } + if (n_historical >= atrlen) + goto leave; /* ATR shorter than required for historical bytes. */ + + if (n_historical) + { + for (idx=0; n_historical && atrlen; n_historical--, atrlen--, atr++) + historical[idx] = *atr; + } + if (!atrlen || *atr != chksum) + goto leave; + /* Don't care about garbage at the end of the ATR. */ + result = n_historical; + leave: + xfree (atrbuffer); + return result; +} |