Web of Trust vs Certificate Authorities – a hybrid approach

The only thing in engineering worse than a single point of failure is multiple single points of failure. A SPOF is a component that the entire system depends upon, and which can thus bring down the entire system single-handedly. MSPOFs are a collection of components any one of which can bring down the entire system single-handedly. The X509 certificate architecture is such a system.

The job of a public key encryption system is to transform the task of securely sharing secret encryption keys into one of reliably verifying publicly-available certificates. Any form of reliable verification must necessarily involve out of band confirmation of the expected data – if an attacker has compromised our communications channel then any confirmation could be faked just as easily as the original communication. Out of band confirmation requires an attacker to simultaneously compromise multiple independent communications channels – this is the rationale behind sending confirmation codes to mobile phones, for example.

The competing verification models

Public key encryption systems typically rely on one of two out of band methods – an Authority or a Web of Trust. An Authority is a person or organisation that is assumed to be both well-known and trustworthy. If a chain of signatures can be established from an Authority to the certificate in question, then the trustworthiness of that certificate is assumed. By contrast, a Web of Trust requires a chain of signatures to be established from each user to the certificate in question – each user acting as his own Authority.

The out of band confirmation of an Authority relies on the shrinkwrap software model – assuming that your software has been delivered via a trustworthy method, then any Authority certificates that were included with your software are by implication verified. A Web of Trust typically relies on personal knowledge – users are assumed to only have signed the certificates of those people they either know personally or have otherwise verified the identity of offline. In this case, “out of band” means “face to face”.

In addition, some PKI systems allow for multiple signature chains to be defined – this is typical in Web of Trust models where the intermediate certificates are usually controlled by ordinary users whose reliability may be questionable. Multiple chains mitigate this risk by providing extra confirmation pathways which collectively provide greater assurance than any single path.

In a Web of Trust model, each user is responsible for cultivating and maintaining his own outgoing signature chains. This means continually assessing the reliability of the downstream certificates, which even with the help of software tools requires a nontrivial amount of work. The reward for this effort is that the reliability of a well-maintained Web of Trust can be made arbitrarily high as more independent chains are established. An Authority model also requires a maintenance overhead, but Authorities are typically large organisations with well-paid staff, and the certificate chains are much shorter. Authorities also tend to use automated verification methods (such as emails) which can be used by an attacker to escalate from one form of compromise to another.

An Authority is thus more easily attacked than a well-maintained Web of Trust, but less easily attacked than a badly-maintained one, and more convenient for the end user.

Why X509 is broken, and how to fix it

X509 has several points of design weakness:

  1. CA distribution is done via shrinkwrap software – but since almost all software is distributed over the internet this is easily subverted.
  2. Only one certificate chain may be established for any certificate – multiple incoming signatures are not supported, so every chain has a single point of failure.
  3. All CAs have the authority to sign any certificate they choose – therefore if one CA certificate is compromised the attacker can impersonate any site on the internet. Thus every certificate verification has multiple single points of failure.

The first two flaws can be addressed by incorporating features from the Web of Trust model:

  1. Web of Trust for Authorities – browser vendors and CAs should agree to sign each other’s signing certificates using an established WoT, thus mitigating against the distribution of rogue certs. Signing certificates not verifiable via the WoT should be ignored by client software, and technical end users can verify the integrity of the entire CA set using established methods.
  2. Multiple signature chains – each public site on the internet should be expected to provide multiple independently signed copies of the same certificate. A site providing only one signature should be treated as insecure by client software.

The third flaw can be addressed by limiting the validity of individual CA certificates. Each signing certificate should contain a field restricting its signatures to a subset of the internet using a b-tree method. A given CA certificate would state that it may only be used to verify leaf certificates whose names, when hashed using SHA256, match a particular N least-significant-bits, where N increases as we travel down the signature chain. Client software should invalidate any signatures made outside the stated b-tree bucket, and deprecate any signing certificate whose bucket is larger than an agreed standard.

(It has been suggested that CAs be geographically restricted, however it is unclear how this could be enforced for non-geographic domains such as .com, and may conflict with a solution to problem 2.)

With these improvements, the Authority model would organically gain many of the strengths of the Web of Trust model, but without imposing a significant burden upon end users.

DNS cache locking on Server 2008

So I’ve been informed that there are some bizarre problems resolving a website that has recently changed providers from digiweb to novara (wasn’t my idea). From elsewhere the new site appears reliably, but from inside our network we are getting the following results:

andgal@nbgal185:~$ host -t any peracton.com
peracton.com has SOA record ns1.novara.ie. hostmaster.host.ie. 2011080416 10800 3600 604800 14400
peracton.com name server ns1.novara.ie.
peracton.com name server ns2.novara.ie.
peracton.com name server ns3.nameserver.ie.
peracton.com mail is handled by 10 smail3.host.ie.
peracton.com has address 80.93.17.28

andgal@nbgal185:~$ host peracton.com
peracton.com has address 78.137.166.130
peracton.com mail is handled by 10 mail2.hosting.digiweb.ie.

The first set of results is the “correct” one, so why is host (and nslookup, and dig, and firefox…) still going to the old address by default? I suspect it is something to do with cache locking on our Server 2008 DNS forwarder. It seems that even after I have forced a fresh request by using “-t any”, the stale cached A record is being returned for normal searches. This is apparently a security measure to protect against cache poisoning. It would appear that the TTL on the old A record was unusually long, which means that I had to flush the cache on the primary DNS forwarder (the backup DNS forwarder is fine, presumably because the old record was never in its cache).

Sure enough, running “dnscmd /clearcache” on the offending server fixed the problem.

 

 

 

 

 

 

 

 

More JIRA shenanigans

As part of my ongoing project to put every management process possible onto JIRA, I have been working on a way to make our internal account codes smarter. Previously, I was using a custom field with predefined values for each account code – this worked well until I wanted to automate certain tests and actions based on account code metadata such as project start/end dates and approval matrices (this issue was also a significant problem). Two methods sprung to mind: either I could define a custom field that could contain structured data, or I could implement the account codes as Jira issues and use issue linking. In my solution I ended up doing a bit of both.

The advantage of using JIRA issues to store account codes is twofold: firstly I can define whatever custom fields I require to hold structured data (e.g. budget holder userids, timestamps) in a format that JIRA can easily understand; and secondly the financial administrators and I can manage this data through a familiar interface. The big disadvantage is that issue linking in JIRA is done through a separate interface from issue creation/editing, meaning a two-stage process for my users. The ideal solution would be a drop-down menu in the issue creation/editing screen, but this means using a custom field – and one I would probably have to write myself.

Being a typical sysadmin, I decided to hack something together with sticky tape and string. I found a likely-looking custom field in the form of the JIRA Database Values Plugin. Using this to tap directly into JIRA’s back-end database I can populate a drop-down menu using some horrendous left joins:

sql.query=select i.id, cv1.stringvalue, cv2.stringvalue, cv3.stringvalue from (select id from jiraissue where project=10200 and issuetype=13) as i left join (select issue, stringvalue from customfieldvalue where customfield=10140) as cv1 on i.id=cv1.issue left join (select issue, stringvalue from customfieldvalue where customfield=10141) as cv2 on i.id=cv2.issue left join (select issue, stringvalue from customfieldvalue where customfield=10142) as cv3 on i.id=cv3.issue order by cv2.stringvalue, cv3.stringvalue;

primarykey.column.number=0
rendering.viewpattern={1,(none)} {2} {3}

The joins are necessary because JIRA uses a relational back end which assumes a fixed number of columns in each table. It handles issues with custom-defined fields by storing the custom field values in a separate table with back-references to the appropriate row in the main table.

The JDVP plugin provides a pretty front end to a custom field that stores the primary key of a database row, which in this case is jiraissue.id. I can then recall the account code issue in a JSS script by passing the primary key to getIssueObject() – the example below is a post-function that I use in an approval workflow to ensure that nobody can approve his own request:

from com.atlassian.jira import ComponentManager

# Only perform functions on Travel Request issues
if(issue.getIssueTypeObject().getId()=="8") :
  cm = ComponentManager.getInstance()
  cfm = cm.getCustomFieldManager()
  im = cm.getIssueManager()

  accountCodeID = issue.getCustomFieldValue(cfm.getCustomFieldObject('customfield_10134'))
  acIssue = im.getIssueObject(int(accountCodeID))
  acBudgetHolder = acIssue.getCustomFieldValue(cfm.getCustomFieldObject('customfield_10070'))
  acEmergencyBudgetHolder = acIssue.getCustomFieldValue(cfm.getCustomFieldObject('customfield_10151'))

  # Set the budget holder to the account code's budget holder, unless that is the reporter.
  # The Java API for custom fields is crap. I'm using a trick here.
  # http://confluence.atlassian.com/pages/viewpage.action?pageId=160835&focusedCommentId=224398519&#comment-224398519
  # DO NOT USE issue.setCustomFieldValue() - it does NOT persist. This is a feature (!)

  cf=cfm.getCustomFieldObject('customfield_10070')
  if issue.getReporter() == acBudgetHolder :
    cf.getCustomFieldType().updateValue(cf,issue,acEmergencyBudgetHolder)
  else :
    cf.getCustomFieldType().updateValue(cf,issue,acBudgetHolder)

I have two things to say about the above. Firstly, scripts in a language where leading whitespace is significant are very difficult to post to blogs. Secondly, I meant everything I said about the custom fields API. In my previous post, I complained about the Java standard library requiring double references – well here’s another example. Read the last ten lines and try to tell me that the developer in question was sober when he designed the interface.

This does exactly what I want (like all good sticky-tape solutions should). The only thing the JDVP did that annoyed me was to always render “Unknown” (or the localisation equivalent) in the case that one of my database fields contained NULL (some of our accounting codes have optional subcodes, for example). After discussions with the developer, I submitted a patch which made the NULL behaviour configurable, and he has included it in the latest release. Thanks, Wim.

Getting Jira to enforce a date field is in the future on issue creation

As part of a new Jira process I am developing, I need to ensure that the date stored in a certain custom field is in the future. I was using the “compare date and time” validator for this, checking to see that the value of the custom field was greater than or equal to that of the issue Created field. This was working well while I was using it on a standard workflow transition, but it bothered me that the user needed to create an issue and then immediately transition it in order for the validation to work. My users are a technical lot, but even they are likely to forget the second step of the process.

You can use validators on the Create Issue transition (if you can find it –  go to the initial step of your workflow and look for “incoming transitions”), but the technique I was using doesn’t work, as the Created field isn’t updated until after the validator is processed and I was thus comparing with Null. I have Misc Workflow Extensions, Jira Suite Utilities and Jira Toolkit installed, but none provided a validator that would compare a date field with anything other than another date field. Luckily I also have the Jira Scripting Suite installed, and I thought this would be a trivial use case. Grab the custom field data using a jython one-liner and compare with the system date.

It wasn’t so simple. Jira returns date custom field values as java.sql.Timestamp objects, which are nontrivial to compare with jython date objects. I then tried using java.util.Calendar instead of the native jython datetime library, thinking that a java.util.Date would be more easily compared with a java.sql.Timestamp because they implement the same interface. This is technically true, but I didn’t want to compare instantaneous times, only dates, and there is no native method for extracting a date-only component (as a Julian date, say) from a java.util.Date object. One might expect to be able to obtain the raw timestamp data and discard the fractional day components (say, by performing an integer division), but this falls foul of time zones.

Jira treats dates as timestamps with zeroed time-of-day components, but the database backend stores this as milliseconds since the Epoch, and this is what is returned in the Timestamp object. A bare date is thus stored as the timestamp of the immediately previous local midnight. In the case of Ireland in summertime, this will cause an off-by-one error in the algorithm if one naïvely performs an integer division by the number of milliseconds in a day. To find the correct number of local days since the Epoch, one must add the current timezone offset to both timestamps before discarding fractional days. The resulting algorithm is thus far from the desired one-liner:

from com.atlassian.jira import ComponentManager
from java.util import Calendar

cfm = ComponentManager.getInstance().getCustomFieldManager()
leavingDate = issue.getCustomFieldValue(cfm.getCustomFieldObject('customfield_10072'))
today = Calendar.getInstance()
tzoffset = today.getTimeZone().getOffset(today.getTimeInMillis())
leavingDateEpoch = (leavingDate.getTime()+tzoffset)//86400000
todayEpoch = (today.getTimeInMillis()+tzoffset)//86400000

if leavingDateEpoch < todayEpoch :
 result = False
 description = "Leaving date cannot be in the past"
 invalid_fields['customfield_10072'] = u"Leaving date cannot be in the past"

It works, but it’s damn ugly. I particularly love the double reference to the today object in line 7. How the Java standard library manages to be so verbose and still so lacking in basic functionality is beyond me. They actually seem to be going in the wrong direction – I found this wonderful piece of documentation on my travels:

int     Date.getTimezoneOffset()
Deprecated. As of JDK version 1.1, replaced by
-(Calendar.get(Calendar.ZONE_OFFSET) + Calendar.get(Calendar.DST_OFFSET)) / (60 * 1000)

Says it all, really.

Windows Script Host error 800c0019 (VBScript)

Came across this gem today on a machine that had recently been upgraded to Server 2008:

Error: System error: -2146697191
Code: 800C0019
Source: msxml3.dll

Turns out that a custom VBScript was sending a form to one of our secure web servers and the certificate chain couldn’t be verified up to the root (even though we bought it from a reputable source). Adding the offending root certificate to the trusted root certificate authorities database fixed the problem.

This does not seem to be documented anywhere on the internet yet, so here it is.

Vuze+feedmytorrents.com, a match made in…?

Despite having played with Democracy Miro, I’m still rather attached to Azureus Vuze for one or two of its useful features*.

Being an addict of US scifi TV, I was excited to discover feedmytorrents.com, which provides vodcast RSS feeds for most current popular US shows, such as my current favourites BSG and Lost. The killer advantage over other RSS sources (such as the excellent EZTV) is that one can subscribe to a particular feed in Miro or Vuze and get precisely one copy of every episode of that show. No more remembering to search mininova to see if the new episode was up yet! This was exactly what I had been waiting for since discovering Democracy Miro’s channels system.**

Of course, it didn’t take long for the system to break. Vuze’s RSS FeedScanner plugin would display a new episode in the list but not start downloading, instead giving a constantly shifting error message: “Init” > “Scanning 1/64…” >>> “Scanning 39/64…” > “Init” (it never seemed to get past 39). This would eventually time out saying “No data”. This affliction would only affect those particular episodes that feedmytorrents had sourced from mininova, but not those from the pirate bay (easily distinguished by the torrent URL). There was nothing wrong with the torrent file itself, as I could right-click > copy link URL and paste it into firefox, which would happily download the torrent and open it in Vuze, the default application. But of course this completely defeated the seamless experience.

I searched on the Vuze forums and found several similar problems reported but few solutions. One suggestion was that the setting “Use URL as referer” might need to be turned off. Sure enough, this worked. For whatever reason, it seems that mininova doesn’t like the HTTP referer field to be set to the “URL”, whichever URL that may be (itself?). Turning this option off (thus sending no referer) didn’t seem to break piratebay torrents (and why should it: this is the behaviour when one types in a URL by hand), so I disabled it on all my feeds. This makes me ask two questions. 1: why isn’t this option off by default and 2: what the hell does the HTTP referer field have to do with it anyway?

* coughcoughtorcoughcough! Interestingly, the latest version (4.1) of Vuze has reskinned itself to look almost exactly like Miro…
** sorry guys, I don’t watch Rocketboom…

Widefox

I’m a Firefox user, but I used to like Opera back in the days before Firefox was available. I changed over once I discovered TabMixPlus and All-In-One Gestures, which collectively replicated most of Opera’s cool features – all except side-docked tabs, which doesn’t seem to be available in Opera any more either.

There are far too many things which like to dock with the top or bottom of my screen. Given that I use a Mac, I already have an extra menu bar to start with anyway. Computer screens are increasingly in widescreen aspect ratio, but documents read best in portrait mode. This is why most blog software (including this one) puts links and metadata at the side of the page rather than at the top, but there are still webapps out there (Google Maps being one of the worst offenders) that have a huge, wasteful banner across the top of the page.

So imagine my joy today when I found this Firefox chrome CSS hack:

Johnathon Weare – Widefox

The dropdown menu placement doesn’t match the tab bar location, but that’s a minor problem. I can now see Google Maps in a slightly less letterboxy format. Woohoo.

The ActiveX effect

In my current job, Microsoft Sharepoint rules. The decision was made long before my time to employ it as the common document repository, and for most people it works reasonably well. I have to force myself to use it though, and I can distil the reasons down to one root cause: ActiveX controls.

In its vanilla, static-page form, Sharepoint is barely functional. It takes a minimum of four clicks (open, edit, modify, save) to change a radio-button option. Checking files in and out is a pain – it’s easier to just overwrite. And I’ve never managed to attach a file to a list entry. To make it really useable, you need to run IE.

Oh wait, you’re using a Mac. Well you can just piss off then.

It’s interesting that Microsoft poured thousands of programmer-hours into developing an alternative to JavaScript and not one of the other browsers makes any attempt to support the resulting spec – this in a world of Mono, Samba, Moonlight and OpenOffice. MS dropped IE support on the Mac but keep pushing ActiveX in their server products. I’m no expert, but the only thing I see ActiveX doing that JS can’t is installing software updates without bothering the user with dialog boxes. Which is a good indication of why nobody else will touch it with a barge pole.

The problem is not confined to Sharepoint. The motivation for this post was finding that Microsoft’s certificate management server requires scripting to be turned on (it doesn’t say what sort of scripting, but it isn’t JS) in order to process a simple form that could have been written in 1995. In this case there was no option but to boot up the VM and use IE.

So what to do? Struggle manfully with Sharepoint’s prehistoric static interface or retreat into the VM, cut off from my usual editing suite – Office X for Mac. Somebody somewhere is no doubt enjoying this juicy irony. But it’s not me.

Back to normal (ish)

I finally got my personal blog back to normal following my LVS account deletion. It was a long process, and proved the wisdom of always keeping a system image as a backup, and not just the files that you think have been modified.

I had forgotten that the wordpress software stores uploaded files under /usr/share/wordpress/, which is completely boneheaded. They should really be under /var, where all well-behaved programs keep their databases. Luckily enough, I had kept copies of all my uploaded pictures. Unfortunately, I can’t find a way to create thumbnails without uploading them all through the web interface one at a time. But most annoyingly, I had performed some surgery on the theme that I was using for gatewaytheatre.org, and all that work has been lost.

I was also reminded, as I was changing the records of all the domains that I manage, of the clunkiness of most DNS registrar web interfaces. What I wanted to do was change every domain I own to use my new virtual server as a nameserver. Every single record had to be changed by hand, using about four or five clicks each. There must be a better way.