aboutsummaryrefslogtreecommitdiffstats
path: root/scd/atr.c
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2008-09-23 09:57:45 +0000
committerWerner Koch <[email protected]>2008-09-23 09:57:45 +0000
commitf899b9683b7123b7bacd5de91fb49fd2412b9116 (patch)
treeb6b89477ec7016c1d9902442db6a98e980d49a5f /scd/atr.c
parent* keyserver.c (keyserver_import_cert): Allow keyserver URLs in (diff)
downloadgnupg-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.c111
1 files changed, 111 insertions, 0 deletions
diff --git a/scd/atr.c b/scd/atr.c
index cb6b05a7d..67a86d09c 100644
--- a/scd/atr.c
+++ b/scd/atr.c
@@ -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;
+}