source: trunk/Sparkle/SUDSAVerifier.m @ 1046

Revision 128, 4.4 KB checked in by speck, 4 years ago (diff)

Fixed missing display of update notes in Sparkle. Embedded Sparkle so subversion has the proper version instead of having to download Sparkle and apply several patches.

Line 
1//
2//  SUDSAVerifier.m
3//  Sparkle
4//
5//  Created by Andy Matuschak on 3/16/06.
6//  Copyright 2006 Andy Matuschak. All rights reserved.
7//
8
9// DSA stuff adapted from code provided by Allan Odgaard. Thanks, Allan!
10
11#import "SUDSAVerifier.h"
12
13#import <stdio.h>
14#import <openssl/evp.h>
15#import <openssl/bio.h>
16#import <openssl/pem.h>
17#import <openssl/rsa.h>
18#import <openssl/sha.h>
19
20long b64decode(unsigned char* str)
21{
22    unsigned char *cur, *start;
23    int d, dlast, phase;
24    unsigned char c;
25    static int table[256] = {
26        -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* 00-0F */
27        -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* 10-1F */
28        -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63,  /* 20-2F */
29        52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1,  /* 30-3F */
30        -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,  /* 40-4F */
31        15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,  /* 50-5F */
32        -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,  /* 60-6F */
33        41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1,  /* 70-7F */
34        -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* 80-8F */
35        -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* 90-9F */
36        -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* A0-AF */
37        -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* B0-BF */
38        -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* C0-CF */
39        -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* D0-DF */
40        -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* E0-EF */
41        -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1   /* F0-FF */
42    };
43   
44    d = dlast = phase = 0;
45    start = str;
46    for (cur = str; *cur != '\0'; ++cur )
47    {
48        if(*cur == '\n' || *cur == '\r'){phase = dlast = 0; continue;}
49        d = table[(int)*cur];
50        if(d != -1)
51        {
52            switch(phase)
53            {
54                case 0:
55                    ++phase;
56                    break;
57                case 1:
58                    c = ((dlast << 2) | ((d & 0x30) >> 4));
59                    *str++ = c;
60                    ++phase;
61                    break;
62                case 2:
63                    c = (((dlast & 0xf) << 4) | ((d & 0x3c) >> 2));
64                    *str++ = c;
65                    ++phase;
66                    break;
67                case 3:
68                    c = (((dlast & 0x03 ) << 6) | d);
69                    *str++ = c;
70                    phase = 0;
71                    break;
72            }
73            dlast = d;
74        }
75    }
76    *str = '\0';
77    return str - start;
78}
79
80EVP_PKEY* load_dsa_key(char *key)
81{
82    EVP_PKEY* pkey = NULL;
83    BIO *bio;
84    if((bio = BIO_new_mem_buf(key, (int)strlen(key))))
85    {
86        DSA* dsa_key = 0;
87        if(PEM_read_bio_DSA_PUBKEY(bio, &dsa_key, NULL, NULL))
88        {
89            if((pkey = EVP_PKEY_new()))
90            {
91                if(EVP_PKEY_assign_DSA(pkey, dsa_key) != 1)
92                {
93                    DSA_free(dsa_key);
94                    EVP_PKEY_free(pkey);
95                    pkey = NULL;
96                }
97            }
98        }
99        BIO_free(bio);
100    }
101    return pkey;
102}
103
104@implementation SUDSAVerifier
105
106+ (BOOL)validatePath:(NSString *)path withEncodedDSASignature:(NSString *)encodedSignature withPublicDSAKey:(NSString *)pkeyString
107{
108    BOOL result = NO;
109    if (!encodedSignature) { return NO; }
110    if (!pkeyString) { return NO; }
111   
112    // Remove whitespace around each line of the key.
113    NSMutableArray *pkeyTrimmedLines = [NSMutableArray array];
114    NSEnumerator *pkeyLinesEnumerator = [[pkeyString componentsSeparatedByString:@"\n"] objectEnumerator];
115    NSString *pkeyLine;
116    while ((pkeyLine = [pkeyLinesEnumerator nextObject]) != nil)
117    {
118        [pkeyTrimmedLines addObject:[pkeyLine stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]];
119    }
120    pkeyString = [pkeyTrimmedLines componentsJoinedByString:@"\n"]; // Put them back together.
121
122    EVP_PKEY* pkey = NULL;
123    pkey = load_dsa_key((char *)[pkeyString UTF8String]);
124    if (!pkey) { return NO; }
125
126    // Now, the signature is in base64; we have to decode it into a binary stream.
127    unsigned char *signature = (unsigned char *)[encodedSignature UTF8String];
128    long length = b64decode(signature); // Decode the signature in-place and get the new length of the signature string.
129   
130    // We've got the signature, now get the file data.
131    NSData *pathData = [NSData dataWithContentsOfFile:path];
132    if (!pathData) { return NO; }
133   
134    // Hash the file with SHA-1.
135    unsigned char md[SHA_DIGEST_LENGTH];
136    SHA1([pathData bytes], [pathData length], md);
137   
138    // Actually verify the signature on the file.
139    EVP_MD_CTX ctx;
140    if(EVP_VerifyInit(&ctx, EVP_dss1()) == 1) // We're using DSA keys.
141    {
142        EVP_VerifyUpdate(&ctx, md, SHA_DIGEST_LENGTH);
143        result = (EVP_VerifyFinal(&ctx, signature, (unsigned int)length, pkey) == 1);
144    }
145   
146    EVP_PKEY_free(pkey);
147    return result;
148}
149
150@end
Note: See TracBrowser for help on using the repository browser.